I use rest api with powershell to get details from the Service Bus queue message. I am not sure when it happened, but now Content is in bytes ex: Content:{64, 6, 115, 116…}.
How can I convert it to the normal string with data?
function Get-SAStoken {
param (
$QueueName,
$Access_Policy_Name,
$Access_Policy_Key
)
$expireInSeconds = 300
[Reflection.Assembly]::LoadWithPartialName("System.Web")| out-null
$uri="my.servicebus.windows.net/$QueueName"
#Token expires now+300
$expires=([DateTimeOffset]::Now.ToUnixTimeSeconds())+ $expireInSeconds
$signatureString=[System.Web.HttpUtility]::UrlEncode($uri)+ "`n" + [string]$expires
$HMAC = New-Object System.Security.Cryptography.HMACSHA256
$HMAC.key = [Text.Encoding]::ASCII.GetBytes($Access_Policy_Key)
$signature = $HMAC.ComputeHash([Text.Encoding]::ASCII.GetBytes($signatureString))
$signature = [Convert]::ToBase64String($signature)
$sasToken = "SharedAccessSignature sr={0}&sig={1}&se={2}&skn={3}" -f [System.Web.HttpUtility]::UrlEncode($uri),
[System.Web.HttpUtility]::UrlEncode($signature),
[System.Web.HttpUtility]::UrlEncode($expires),
[System.Web.HttpUtility]::UrlEncode($Access_Policy_Name)
return $sasToken
}
function Get-SBmessage {
param (
$SASToken,
$Queue
)
$queue = $Queue
$header = #{ Authorization = $SASToken }
$postService = Invoke-WebRequest -Uri "https://my.servicebus.windows.net/$queue/messages/head" `
-Headers $header `
-Method Post
return $postService
}
$Queue = "capacity-checker"
$SAStokenRunningTest = Get-SAStoken -QueueName $Queue -Access_Policy_Name "pipeline" -Access_Policy_Key "key-for-sb-queue"
$SBmessage = Get-SBmessage -SASToken $SAStokenRunningTest -Queue $Queue
$SBmessage
So my solution is
[byte[]]$bytes = $SBmessage.Content
$msContent = [System.Text.Encoding]::ASCII.GetString($bytes)
Thanks, #MathiasR.Jessen for the help
Related
I try to write a PowerShell Script and test it using https://api.binance.com/api/v3/order/test REST link but it doesn't work. I can't understand what should I use as message, what as body and what as header. It seems that here everything is clear and when I see a linux example I should have the same link in Output:
https://github.com/binance-exchange/binance-official-api-docs/blob/master/rest-api.md
Could someone who understands REST Post method help me to figure out what should I change here.
My output is:
POST https://api.binance.com/api/v3/order/test?symbol=LTCBTC&side=BUY&type=LIMIT&timeInForce=GTC&quantity=1&price=0.1&recvWindow=5000×tamp=1515586306172&signature=LxHZUfC5MiTUfMPyEtgaVShlV1j4ITo3QxvtPAzPkwQ=
Many thanks in advance.
$apiKey = "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"
$unixEpochStart = Get-Date -Date "01/01/1970"
$now = Get-Date
$timestamp = (New-TimeSpan -Start $unixEpochStart -End $now.ToUniversalTime()).TotalMilliseconds
$timestamp = ([math]::Round($timestamp, 0)).ToString()
$apimessage = "symbol=LTCBTC&side=BUY&type=LIMIT&timeInForce=GTC&quantity=1&price=0.1&recvWindow=5000×tamp=$timestamp"
$apisecret = "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"
$hmacsha = New-Object System.Security.Cryptography.HMACSHA256
$hmacsha.key = [Convert]::FromBase64String($apisecret)
$signature = $hmacsha.ComputeHash([Text.Encoding]::ASCII.GetBytes($apimessage))
$signature = [Convert]::ToBase64String($signature)
$uri = "https://api.binance.com/api/v3/order/test?$apimessage&signature=$signature"
$header = #{
"X-MBX-APIKEY" = $apiKey
}
Invoke-RestMethod -Method Post -Uri $uri -Headers $header -Verbose
The issue is this line of code:
$signature = [Convert]::ToBase64String($signature)
Binance expects the HMAC SHA256 transmitted in hex form. Replace the above with this and the issue should be resolved.
$signature = [System.BitConverter]::ToString($signature).Replace('-', '').ToLower()
Below is my working code.
APIKey and Secret are from the example of the Binance API doc
https://github.com/binance-exchange/binance-official-api-docs/blob/master/rest-api.md#signed-endpoint-examples-for-post-apiv1order
Result of $Signature should be the same as in the Binance example: c8db56825ae71d6d79447849e617115f4a920fa2acdcab2b053c4b2838bd6b71
If you use your own APIKey and Secret it should be working
$APIKey = "vmPUZE6mv9SD5VNHk4HlWFsOr6aKE2zvsw0MuIgwCIPy6utIco14y7Ju91duEh8A"
$APISecret = "NhqPtmdSJYdKjVHjA7PZj4Mge3R5YNiP1e3UZjInClVN65XAbvqqM6A7H5fATj0j"
$TimeStamp = (Get-Date (Get-Date).ToUniversalTime() -UFormat %s).replace(',', '').replace('.', '').SubString(0,13)
$QueryString = "symbol=LTCBTC&side=BUY&type=LIMIT&timeInForce=GTC&quantity=1&price=0.1&recvWindow=5000×tamp=1499827319559"
$hmacsha = New-Object System.Security.Cryptography.HMACSHA256
$hmacsha.key = [Text.Encoding]::ASCII.GetBytes($APISecret)
$signature = $hmacsha.ComputeHash([Text.Encoding]::ASCII.GetBytes($QueryString))
$signature = [System.BitConverter]::ToString($signature).Replace('-', '').ToLower()
$uri = "https://api.binance.com/api/v3/account?$QueryString&signature=$signature"
$headers = New-Object "System.Collections.Generic.Dictionary[[String],[String]]"
$headers.Add("X-MBX-APIKEY",$APIKey)
try {
Invoke-RestMethod -Uri $uri -Headers $headers -Method Get
}
Catch {
$streamReader = [System.IO.StreamReader]::new($_.Exception.Response.GetResponseStream())
$ErrResp = $streamReader.ReadToEnd() | ConvertFrom-Json
$streamReader.Close()
$ErrResp
}
below all the functions you need to request the Binance API.
Reference: https://blog.p-difm.com/interact-with-your-binance-account-using-the-api-and-powershell/
function Get-UnixTimeStamp{
<#
.SYNOPSIS
Return the timestamp in millisecond of the Unix Epoch
.DESCRIPTION
Unix Epoch started the Thursday, January 1, 1970 12:00:00 AM. The function return the number of second from that time.
.EXAMPLE
Get-UnixTimeStamp
#>
param(
)
return $(Get-Date (Get-Date).ToUniversalTime() -UFormat %s).replace(',', '').replace('.', '').SubString(0,13)
}
function Get-BinanceAPISignature{
<#
.SYNOPSIS
Prepare the signature that will be sent with the API request
.DESCRIPTION
Endpoint requires sending a valid API-Key and signature
.PARAMETER QueryString
The queryString must contains the symobol, timestamp and a recvWindow
.PARAMETER EndPoint
The EndPoint you want to request
.EXAMPLE
$URI = Get-BinanceAPISignature -QueryString $QueryString -EndPoint "/api/v3/openOrders"
#>
param(
[Parameter(Mandatory=$true)]$QueryString,
[Parameter(Mandatory=$true)]$EndPoint
)
$APISecret = "ASDHFASUHDFIOUSAHlUGLULUHALUHliuhalushduauauhIUH"
$hmacsha = New-Object System.Security.Cryptography.HMACSHA256
$hmacsha.key = [Text.Encoding]::ASCII.GetBytes($APISecret)
$signature = $hmacsha.ComputeHash([Text.Encoding]::ASCII.GetBytes($QueryString))
$signature = [System.BitConverter]::ToString($signature).Replace('-', '').ToLower()
$URI = "https://api.binance.com$($EndPoint)?$QueryString&signature=$signature"
return $URI
}
function Get-BinanceAPIHeader{
<#
.SYNOPSIS
Prepare the header that will be sent with the API request
.DESCRIPTION
The header include your APIKey
.PARAMETER
#APIKey
.EXAMPLE
Get-BinanceAPIHeader
#>
param(
)
$APIKey = "HDAUSHF3989898hiuHGhuhI987898HiuahsduhaiusduhUIH"
$Headers = New-Object "System.Collections.Generic.Dictionary[[String],[String]]"
$Headers.Add("X-MBX-APIKEY",$APIKey)
return $Headers
}
function Request-API{
<#
.SYNOPSIS
Run the CURL command with defined parameters
.DESCRIPTION
Call the API and error handling. Return the result of the request
.PARAMETER Method
Choose a method according to the EndPoint
.PARAMETER URI
This parameter needs to be obtained with Get-BinanceAPISignature
.PARAMETER Headers
This parameter needs to be obtained with Get-BinanceAPIHeaderx
.EXAMPLE
$ObjResults = Request-API -Method Get -URI $URI -Headers $Headers
#>
[cmdletbinding()]
param(
[Parameter(Mandatory=$true)][ValidateSet("POST","GET","DELETE")]$Method,
[Parameter(Mandatory=$true)]$URI,
[Parameter(Mandatory=$true)]$Headers
)
try{
$ArrayJsonResult = Curl $URI -Method $Method -Headers $Headers #-Verbose
$ObjCustomResult = $ArrayJsonResult.Content | ConvertFrom-Json
}
catch{
$streamReader = [System.IO.StreamReader]::new($_.Exception.Response.GetResponseStream())
$ErrResp = $streamReader.ReadToEnd() | ConvertFrom-Json
$streamReader.Close()
$LastError = $Error[0].ErrorDetails.Message | ConvertFrom-Json
write-host "1: " $ErrResp -b Red
write-host "2: " $LastError.code -b Red
write-host "3: " $LastError.msg -b Red
switch ($LastError.code){
("-1105") {write-host "TimeStamp issue"}
("-1003") {write-host "Too much request, IP Banned"; break}
("-2010") {write-host "Stop price would trigger immediately or Account has too many open stop loss and/or take profit orders on the symbol."}
("-1013") {write-host "The amount is not enough for this currency or not following the step size rule for the symbol."}
("-1111") {write-host "Too many decimal check the precision required with Get-ExchangeInfo"}
}
}
return $ObjCustomResult
}
And here an example how to use it
Reference: https://blog.p-difm.com/new-order-with-api-binance-and-powershell/
function New-Order{
<#
.SYNOPSIS
Place an order to buy or sell crypto
.PARAMETER Symbol
The crypto you want to buy or sell
.PARAMETER Side
ValidateSet "BUY" or "SELL"
.PARAMETER OrderType
ValidateSet "OrderMarket" or "OrderLimit" or "OrderStopLimit"
.PARAMETER Quantity
Specifies the amount you want to spend (when buying) or receive (when selling)
.PARAMETER FiatAmount
specifies the amount you want to spend in USDT
.EXAMPLE
New-Order -Symbol BTCUSDT -Side BUY -OrderType OrderMarket -FiatAmount 20 -Verbose
.EXAMPLE
New-Order -Symbol BTCUSDT -Side BUY -OrderType OrderLimit -FiatAmount 1000 -Price 33000
.EXAMPLE
New-Order -Symbol BTCUSDT -Side BUY -OrderType OrderStopLimit -Quantity 0.002 -Price 33000 -StopPrice 36000
.EXAMPLE
New-Order -Symbol XRPUSDT -Side SELL -OrderType OrderLimit -Quantity 100 -Price 0.5
.EXAMPLE
New-Order -Symbol XRPUSDT -Side SELL -OrderType OrderStopLimit -Quantity 100 -Price 0.55 -StopPrice 0.5
#>
[cmdletbinding()]
param(
[Parameter(Mandatory=$true)]
[string]$Symbol,
[Parameter(Mandatory=$true)]
[ValidateSet("BUY", "SELL")]
[string]$Side,
[Parameter(Mandatory=$true)]
[ValidateSet("OrderMarket", "OrderLimit", "OrderStopLimit")]
[string]$OrderType,
[Parameter(Mandatory=$true, ParameterSetName = 'quantity')]
[double]$Quantity,
[Parameter(Mandatory=$true, ParameterSetName = 'quantity2')]
[double]$FiatAmount
)
DynamicParam{
$paramDictionary = New-Object -Type System.Management.Automation.RuntimeDefinedParameterDictionary
if ($OrderType -ne "OrderMarket"){
# price param
$attributes = New-Object -Type System.Management.Automation.ParameterAttribute
$attributes.Mandatory = $true
$attributeCollection = New-Object -Type System.Collections.ObjectModel.Collection[System.Attribute]
$attributeCollection.Add($attributes)
$dynParam1 = New-Object -Type System.Management.Automation.RuntimeDefinedParameter("Price", [double], $attributeCollection)
$paramDictionary.Add("Price", $dynParam1)
}
if ($OrderType -eq "OrderStopLimit"){
# StopPrice param
$attributes2 = New-Object -Type System.Management.Automation.ParameterAttribute
$attributes2.Mandatory = $true
$attributeCollection2 = New-Object -Type System.Collections.ObjectModel.Collection[System.Attribute]
$attributeCollection2.Add($attributes2)
$dynParam2 = New-Object -Type System.Management.Automation.RuntimeDefinedParameter("StopPrice", [double], $attributeCollection2)
$paramDictionary.Add("StopPrice", $dynParam2)
}
return $paramDictionary
}
BEGIN{
# Check prerequisit
try{
Get-Command -Name Get-UnixTimeStamp -ErrorAction Stop | out-null
Get-Command -name Get-BinanceAPISignature -ErrorAction Stop | Out-Null
Get-Command -Name Get-BinanceAPIHeader -ErrorAction Stop | Out-Null
Get-Command -Name Request-API -ErrorAction Stop | Out-Null
}
catch{
Write-Host "Load Get-UnixTimeStamp, Get-BinanceAPISignature, Get-BinanceAPIHeader, Request-API first prior to laod the current script" -b red
Break
}
$TimeStamp = Get-UnixTimeStamp
# retrieve value from dyn param
if ($OrderType -ne "OrderMarket"){
$Price = $paramDictionary.values[0].value[0]
$StopPrice = $paramDictionary.values[0].value[1]
}
switch($OrderType){
"OrderMarket"{
if($PSBoundParameters.ContainsKey('Quantity')){
$QueryString = "symbol=$Symbol&side=$Side&type=MARKET&quantity=$Quantity×tamp=$TimeStamp&recvWindow=5000"
}
else{
$QueryString = "symbol=$Symbol&side=$Side&type=MARKET"eOrderQty=$FiatAmount×tamp=$TimeStamp&recvWindow=5000"
}
}
"OrderLimit"{
if($PSBoundParameters.ContainsKey('FiatAmount')){
$CurrentPrice = Get-Price -Symbol $Symbol -Decimal 8
$Quantity = [math]::Round($FiatAmount / $CurrentPrice, 6)
}
$QueryString = "symbol=$Symbol&side=$Side&type=LIMIT&price=$Price&timeInForce=GTC&quantity=$Quantity×tamp=$TimeStamp&recvWindow=5000"
}
"OrderStopLimit"{
if($PSBoundParameters.ContainsKey('FiatAmount')){
$CurrentPrice = Get-Price -Symbol $Symbol -Decimal 0
$Quantity = [math]::Round($FiatAmount / $CurrentPrice, 6)
}
$QueryString = "symbol=$Symbol&side=$Side&type=TAKE_PROFIT_LIMIT&stopPrice=$StopPrice&price=$Price&timeInForce=GTC&quantity=$Quantity×tamp=$TimeStamp&recvWindow=5000"
}
}
}
PROCESS{
$URI = Get-BinanceAPISignature -QueryString $QueryString -EndPoint "/api/v3/order"
$Headers = Get-BinanceAPIHeader
$ObjResults = $null # need to do this?
$ObjResults = Request-API -Method POST -URI $URI -Headers $Headers
}
END{
return $ObjResults
}
}
I am trying to call a web service. If I just start up Powershell fresh, the following code runs perfectly. Any subsequent run will give the following error.
Cannot convert argument "fieldsWithValues", with value:
"FileHold.LibraryManager.FieldWithValue[]", for "SetMetadata" to type
"FileHold.LibraryManager.FieldWithValue[]": "Cannot convert the
"FileHold.LibraryManager.FieldWithValue" value of type
"FileHold.LibraryManager.FieldWithValue" to type
"FileHold.LibraryManager.FieldWithValue"."
At Z:\VM_Transfer\Customers\Oregon\UpdateMetadata\CannotConvertTest.ps1:19 char:1
Here is the code with the problem.
$fh = "http://fileholdtest8/fh/filehold"
$uri = $fh + "/UserRoleManager/SessionManager.asmx?WSDL"
$SessionManager = New-WebServiceProxy -Uri $uri -Namespace FileHold.SessionManager
$sessionId = $SessionManager.StartSession( 'sysadm', '12345', 4 )
$uri = $fh + "/LibraryManager/DocumentManager.asmx?WSDL"
$dm = New-WebServiceProxy -Uri $uri -Namespace FileHold.LibraryManager
$dm.CookieContainer = New-Object System.Net.CookieContainer
$cookie = New-Object System.Net.Cookie( 'FHLSID', $sessionId, "/", ([System.Uri]$dm.Url).Host )
$dm.CookieContainer.Add( $cookie )
$newFieldValue = [FileHold.LibraryManager.FieldWithValue]::new()
$newFieldValue.FieldId = 1007
$newFieldValue.FieldValue = $true
[FileHold.LibraryManager.FieldWithValue[]]$fieldsWithValues = #( $newFieldValue )
$dm.SetMetadata( 4033, 1002, "EmployeeInfo_filled1-test", $fieldsWithValues, $false, $null )
What do I need to do to be able to run this every time without restarting the ISE.
Btw. I can use this technique to call other methods without any problem as long as their parameters are simple types. It seems the issue only occurs when I have a complex object like FileHold.LibraryManager.FieldWithValue.
PSVersion = 5.1.14393.1532
I found a solution by ensuring I do not reuse the variable. Of course, I will need to deal with a potential expired cookie, but that is another problem.
$fh = "http://fileholdtest8/fh/filehold"
$uri = $fh + "/UserRoleManager/SessionManager.asmx?WSDL"
$SessionManager = New-WebServiceProxy -Uri $uri -Namespace FileHold.SessionManager
$sessionId = $SessionManager.StartSession( 'sysadm', '12345', 4 )
if ( !(Test-Path variable:dm) )
{
$uri = $fh + "/LibraryManager/DocumentManager.asmx?WSDL"
$dm = New-WebServiceProxy -Uri $uri -Namespace FileHold.Library
$FieldWithValueType = "{0}.FieldWithValue" -f $dm.GetType().Namespace
$dm.CookieContainer = New-Object System.Net.CookieContainer
$cookie = New-Object System.Net.Cookie( 'FHLSID', $sessionId, "/", ([System.Uri]$dm.Url).Host )
$dm.CookieContainer.Add( $cookie )
}
$newFieldValue = [FileHold.Library.FieldWithValue]::new()
$newFieldValue.FieldId = 1007
$newFieldValue.FieldValue = $true
$fieldsWithValues = #( ,$newFieldValue )
$dm.SetMetadata( 4041, 1002, "EmployeeInfo_filled1-test", $fieldsWithValues, $false, $null )
I've been struggling with what appears to be a common problem: formatting my authorization header for the Azure Table Service REST API. I have been unable to find an example using PowerShell and SharedKey, and am worried that I am making some dumb mistake in working backwards from other examples.
The specific (though unspecific) error is: Server failed to authenticate the request. Make sure the value of Authorization header is formed correctly including the signature.
I have been referencing these articles, as well as other examples:
https://learn.microsoft.com/en-us/rest/api/storageservices/fileservices/Authentication-for-the-Azure-Storage-Services?redirectedfrom=MSDN
https://learn.microsoft.com/en-us/rest/api/storageservices/fileservices/addressing-table-service-resources
I've confirmed that my key is correct, the table exists, has at least one row, and a number of other suggestions without luck.
If there is another approach I should take to accomplish the same goal, I'm all ears. I would like to use the REST API to allow for maximum compatibility on the clients.
$tableEndpoint = 'https://STORAGEACCOUNTNAME.table.core.windows.net/'
$tableName = 'TABLENAME'
$StorageAccountName = 'STORAGEACCOUNTNAME'
$Key = "STORAGEACCOUNTKEY"
Function New-AuthorizationHeader
{
param ($canonicalizedString)
[byte[]]$Bytes = [system.convert]::FromBase64String($Key)
$HMACSHA256 = [System.Security.Cryptography.HMACSHA256]::new($Bytes)
$dataToHmac = [System.Text.Encoding]::UTF8.GetBytes($canonicalizedString)
$Signature = [System.Convert]::ToBase64String($HMACSHA256.ComputeHash($dataToHmac))
[string]$AuthorizationHeader = "{0} {1}:{2}" -f "SharedKey",$StorageAccountName,$Signature
$AuthorizationHeader
}
Function New-Entity
{
param ($jsonContent)
$requestMethod = "POST"
$contentMD5 = [string]::Empty
$storageServiceVersion = '2016-05-31'
$reqDate = (Get-Date -Format r)
$contentType = "application/json"
$canonicalizedResource = "/{0}/{1}" -f $StorageAccountName,($tableEndpoint + $tableName)
$stringToSign = "{0}`n{1}`n{2}`n{3}`n{4}" -f $requestMethod,$contentMD5,$contentType,$reqDate,$canonicalizedResource
$authorizationHeader = New-AuthorizationHeader -canonicalizedString $stringToSign
$content = [System.Text.Encoding]::UTF8.GetBytes($jsonContent)
$fullURI = New-Object -TypeName System.Uri -ArgumentList ($tableEndpoint + $tableName)
$httpWebRequest = [System.Net.WebRequest]::Create($fullURI)
$httpWebRequest.Accept = 'application/json;odata=fullmetadata'
$httpWebRequest.ContentLength = $content.length
$httpWebRequest.ContentType = $contentType
$httpWebRequest.Method = $requestMethod
$httpWebRequest.Headers.Add("x-ms-date", $reqDate)
$httpWebRequest.Headers.Add("x-ms-version", $storageServiceVersion)
$httpWebRequest.Headers.Add("Authorization", $authorizationHeader)
$httpWebRequest.Headers.Add("Accept-Charset", "UTF-8")
$httpWebRequest.Headers.Add("DataServiceVersion", "3.0;NetFx")
$httpWebRequest.Headers.Add("MaxDataServiceVersion", "3.0;NetFx")
$requestStream = $httpWebRequest.GetRequestStream()
$requestStream.Write($content, 0, $content.length)
$requestStream.Close()
$response = $httpWebRequest.GetResponse()
$dataStream = $response.GetResponseStream()
$reader = New-Object -TypeName System.IO.StreamReader($dataStream)
$responseFromServer = $reader.ReadToEnd()
}
$jsonContent = #"
{
"ExecutionStatus"="smapledata",
"PartitionKey"="$ENV:Username",
"RowKey"="PrinterScript"
}
"#
New-Entity -jsonContent $jsonContent
Please make 2 changes above:
Canonical resource should not have table endpoint. So it should be:
$canonicalizedResource = "/{0}/{1}" -f $StorageAccountName,$tableName
JSON body should be properly formatted. So it should be:
$jsonContent = #"
{
"ExecutionStatus":"smapledata",
"PartitionKey":"$ENV:Username",
"RowKey":"PrinterScript"
}
"#
Once you make these changes, the code should work just fine.
Thank you again for your responses, Gaurav.
I verified that my clock is not skewed. In the end, I switched to using a Shared Access Signature, which is probably a better practice anyway.
Using a SAS obviates the need for an Authorization header (and getting that correctly formatted).
Here's the relevant updated PowerShell:
$tableEndpoint = 'https://STORAGEACCOUNT.table.core.windows.net/'
$tableName = 'TABLENAME'
$SAS = "?sv=2016-05-31&ss=t&srt=o&sp=wa&se=2017-09-01T04:08:11Z&st=2017-03-14T20:08:11Z&spr=https&sig=SIGNATURE"
$URI = $tableEndpoint + $tableName + $SAS
If (-NOT $script:RunLogKeyTime)
{
$script:RunLogKeyTime = (Get-Date -Format 'yyyyMMdd-HHmmss')
}
$RequestBody = ConvertTo-Json -InputObject #{
"TagetName"= $TargetName;
"Message"= $Message;
"ComputerName"= $ENV:ComputerName;
"Username"= $ENV:Username;
"EntryType"= $EntryType;
"PartitionKey"= "$Username`_$ScriptIdentifier";
"RowKey"= "$EntryType"}
$EncodedRequestBody = [System.Text.Encoding]::UTF8.GetBytes($RequestBody)
$RequestHeaders = #{
"x-ms-date"=(Get-Date -Format r);
"x-ms-version"="2016-05-31";
"Accept-Charset"="UTF-8";
"DataServiceVersion"="3.0;NetFx";
"MaxDataServiceVersion"="3.0;NetFx";
"Accept"="application/json;odata=nometadata";
"ContentLength"=$EncodedRequestBody.Length}
Invoke-WebRequest -Method POST -Uri $URI -Headers $RequestHeaders -Body $EncodedRequestBody -ContentType "application/json"
After attempting several different examples I am unable to update list items using the Sharepoint REST API. I receive back a 400 error from the request.
The creplace is due to Sharepoint sending both ID and Id for some reason and breaking the ConvertFrom-Json in my Get-SPListItems method.
function Update-SPListItems
{
param
(
$listUpdate
)
$requestDigest = Get-RequestDigest
foreach($item in $listUpdate.Results)
{
$restUrl = $item.__metadata.uri
$item.tsFeedbackStatus = "Open"
$item.Modified = Get-Date -Format s
$updatedItem = $item | ConvertTo-Json
#convert back the duplicate field
$updatedItem = $updatedItem -creplace '"ignoreId":','"Id":'
$itemJsonBytes = [System.Text.Encoding]::ASCII.GetBytes($updatedItem)
try
{
#examples have shown POST/MERGE, POST/PATCH, MERGE/MERGE,
#PATCH/PATCH, none of them in those combinations have worked
$request = [System.Net.WebRequest]::Create($restUrl)
$request.Credentials = $Credential.GetNetworkCredential()
$request.Headers.Add("X-FORMS_BASED_AUTH_ACCEPTED", "f")
$request.Headers.Add("If-Match", "*")
$request.Headers.Add("X-RequestDigest", $requestDigest)
$request.Headers.Add("X-HTTP-Method", "MERGE")
$request.Accept = "application/json;odata=verbose"
$request.Method = "POST"
$request.ContentType = "application/json;odata=verbose"
$request.ContentLength = $itemJsonBytes.Length
$stream = $request.GetRequestStream()
$stream.Write($itemJsonBytes, 0, $itemJsonBytes.Length)
$stream.Close()
$response = $request.GetResponse()
}
catch [System.Exception]
{
Write-Error $_.Exception.ToString()
}
}
}
Here is the exact error:
Update-SPListItems : System.Net.WebException: The remote server returned an error: (400) Bad Request.
at System.Net.HttpWebRequest.GetResponse()
at CallSite.Target(Closure , CallSite , Object )
At C:\Users\user\Desktop\SPListTest.ps1:120 char:11
$result = Update-SPListItems $list
~~~~~~~~~~~~~~~~~~~~~~~~
CategoryInfo : NotSpecified: (:) [Write-Error], WriteErrorException
FullyQualifiedErrorId : Microsoft.PowerShell.Commands.WriteErrorException,Update-SPListItems
Try the below reusable function for this. It worked for me every time. Ensure to pass the parameters properly. This has authentication built into it and even works for older versions of PowerShell.
function Request-Rest{
[CmdletBinding()]
PARAM (
[Parameter(Mandatory=$False)]
[String]$Metadata,
[Parameter(Mandatory=$true)]
[String] $URL,
[Parameter(Mandatory=$False)]
[Switch]$listUpdate,
[Parameter(Mandatory=$False)]
[String]$RequestDigest,
[Parameter(Mandatory=$false)]
[Microsoft.SharePoint.Client.SharePointOnlineCredentials] $credentials,
[Parameter(Mandatory=$false)]
[String] $UserAgent = "PowerShell API Client",
[Parameter(Mandatory=$false)]
[Switch] $JSON,
[Parameter(Mandatory=$false)]
[Switch] $Raw
)
#Create a URI instance since the HttpWebRequest.Create Method will escape the URL by default.
#$URL = Fix-Url $Url
$URI = New-Object System.Uri($URL,$true)
#Create a request object using the URI
$request = [System.Net.HttpWebRequest]::Create($URI)
#Build up a User Agent
$request.UserAgent = $(
"{0} (PowerShell {1}; .NET CLR {2}; {3})" -f $UserAgent, $(if($Host.Version){$Host.Version}else{"1.0"}),
[Environment]::Version,
[Environment]::OSVersion.ToString().Replace("Microsoft Windows ", "Win")
)
if ($credentials -eq $null)
{
$request.UseDefaultCredentials = $true
}
else
{
$request.Credentials = $credentials
}
$request.Headers.Add("X-FORMS_BASED_AUTH_ACCEPTED", "f")
#Request Method
$request.Method = "POST"
#Headers
if($listUpdate)
{
$request.Headers.Add("X-RequestDigest", $RequestDigest)
$request.Headers.Add("If-Match", "*")
$request.Headers.Add("X-HTTP-Method", "MERGE")
$request.ContentType = "application/json;odata=verbose"
$request.Accept = "application/json;odata=verbose"
}
#Request Body
if($Metadata) {
$Body = [byte[]][char[]]$Metadata
$request.ContentLength = $Body.Length
$stream = $request.GetRequestStream()
$stream.Write($Body, 0, $Body.Length)
}
else {
$request.ContentLength = 0
}
try
{
[System.Net.HttpWebResponse] $response = [System.Net.HttpWebResponse] $request.GetResponse()
}
catch
{
Throw "Exception occurred in $($MyInvocation.MyCommand): `n$($_.Exception.Message)"
}
$reader = [IO.StreamReader] $response.GetResponseStream()
if (($PSBoundParameters.ContainsKey('JSON')) -or ($PSBoundParameters.ContainsKey('Raw')))
{
$output = $reader.ReadToEnd()
}
else
{
$output = $reader.ReadToEnd()
}
$reader.Close()
if($output.StartsWith("<?xml"))
{
[xml]$outputXML = [xml]$output
}
else
{
[xml]$outputXML = [xml] ("<xml>" + $output + "</xml>")
}
Write-Output $outputXML
$response.Close()
}
Read over the stackoverflow for the answer, still can't find what causing this..
Trying to connect and send a POST request using powershell, and getting "unable to connect to remote server" error. Tried 3 different dummy servers like http://posttestserver.com/post.php
Script:
Get-ExecutionPolicy
[string]$url = "http://posttestserver.com/post.php"
function Execute-HTTPPostCommand()
{
param([string]$target = $null)
#$username = "administrator"
#$password = "mypass"
$webRequest = [System.Net.WebRequest]::Create($target)
$webRequest.ContentType = "text/html"
$post = "abcdefg"
$PostStr = [System.Text.Encoding]::UTF8.GetBytes($Post)
$webrequest.ContentLength = $PostStr.Length
$webRequest.ServicePoint.Expect100Continue = $false
#$webRequest.Credentials = New-Object System.Net.NetworkCredential -ArgumentList $username, $password
#$webRequest.PreAuthenticate = $true
$webRequest.Method = "POST"
try
{
$requestStream = $webRequest.GetRequestStream()
}
catch
{
write-host $_.Exception
}
$requestStream.Write($PostStr, 0,$PostStr.length)
$requestStream.Close()
[System.Net.WebResponse]$resp = $webRequest.GetResponse();
$rs = $resp.GetResponseStream();
[System.IO.StreamReader]$sr = New-Object System.IO.StreamReader -argumentList $rs;
[string]$results = $sr.ReadToEnd();
return $results;
}
Execute-HTTPPostCommand $url
[System.GC]::Collect()