Powershell HTTP POST File Upload for REST api - api

I am new to Powershell and having trouble sending a file via an HTTP POST request. Everything is working perfectly except for sending/uploading the file. Is this possible using my existing code?
Here is my code:
# VARIABLES
$myFile = "c:\sample_file.csv"
$updateUrl = "http://www.example.com/processor"
$postData = "field1=value1"
$postData += "&field2=value2"
$postData += "&myFile=" + $myFile
# EXECUTE FUNCTION
updateServer -url $updateUrl -data $postData
function updateServer {
param(
[string]$url = $null,
[string]$data = $null,
[System.Net.NetworkCredential]$credentials = $null,
[string]$contentType = "application/x-www-form-urlencoded",
[string]$codePageName = "UTF-8",
[string]$userAgent = $null
);
if ( $url -and $data ){
[System.Net.WebRequest]$webRequest = [System.Net.WebRequest]::Create($url);
$webRequest.ServicePoint.Expect100Continue = $false;
if ( $credentials ){
$webRequest.Credentials = $credentials;
$webRequest.PreAuthenticate = $true;
}
$webRequest.ContentType = $contentType;
$webRequest.Method = "POST";
if ( $userAgent ){
$webRequest.UserAgent = $userAgent;
}
$enc = [System.Text.Encoding]::GetEncoding($codePageName);
[byte[]]$bytes = $enc.GetBytes($data);
$webRequest.ContentLength = $bytes.Length;
[System.IO.Stream]$reqStream = $webRequest.GetRequestStream();
$reqStream.Write($bytes, 0, $bytes.Length);
$reqStream.Flush();
$resp = $webRequest.GetResponse();
$rs = $resp.GetResponseStream();
[System.IO.StreamReader]$sr = New-Object System.IO.StreamReader -argumentList $rs;
$sr.ReadToEnd();
}
}

Two thoughts. First it seems you're uploading the filename but not the file's contents. Second, if you upload the file's contents within the POST you're likely going to need to URL encode the data using something like [System.Web.HttpUtility]::UrlEncode(). Also, check out my answer to this related SO question.

I found the solution to this problem here. I think I may have come across this when I was building my script originally or a snippet of it somewhere else as it is nearly identical to what I have except more thorough.

Related

laravel 7 pdf-to-text | Could not read pdf file

I installed this laravel package to convert pdf file into text. https://github.com/spatie/pdf-to-text
I'm getting this error:
Could not read sample_1610656868.pdf
I tried passing the file statically by putting it in public folder and by giving path of uploaded file.
Here's my controller:
public function pdftotext(Request $request)
{
if($request->hasFile('file'))
{
// Get the file with extension
$filenameWithExt = $request->file('file')->getClientOriginalName();
//Get the file name
$filename = pathinfo($filenameWithExt, PATHINFO_FILENAME);
//Get the ext
$extension = $request->file('file')->getClientOriginalExtension();
//File name to store
$fileNameToStore = $filename.'_'.time().'.'.$extension;
//Upload File
$path = $request->file('file')->storeAS('public/ebutifier/pdf', $fileNameToStore);
}
// dd($path);
$location = public_path($path);
// $pdf = $request->input('file');
// dd($location);
// echo Pdf::getText($location, 'usr/bin/pdftotext');
$text = (new Pdf('public/ebutifier/pdf/'))
->setPdf($fileNameToStore)
->text();
return $text;
}
Not sure why it's not working any help would be appreciated.
You used spatie/pdf-to-text Package.
I also tried to use this package but it gave me this kind of error.
So, I used asika/pdf2text package and it worked properly
Asika/pdf2text pacakge
And this is my code
$path = public_path('/uploads/documents/'. $file_name);
$reader = new \Asika\Pdf2text;
$output = $reader->decode($path);
dd($output);
Hopefully, it will be helpful for you.

Coinbase API invalid signature with Powershell

I would like to retrieve account balance through Coinbase API with Powershell.
I coded the following reading from coinbase api documentation but the last request throws the following error:
Invoke-RestMethod : {"errors":[{"id":"authentication_error","message":"invalid signature"}]}
Here is my code.
What's wrong? Thank you.
$accounts = 'https://api.coinbase.com/v2/accounts'
$time = 'https://api.coinbase.com/v2/time'
$epochtime = [string]((Invoke-WebRequest $time | ConvertFrom-Json).data).epoch
$method = 'GET'
$requestpath = '/v2/accounts'
$secret_key = 'xxxxxxxxxxxxxxxxxxxxxxxxxxxxx'
$sign = $epochtime + $method + $requestpath
$hmacsha = New-Object System.Security.Cryptography.HMACSHA256
$hmacsha.key = [Convert]::FromBase64String($secret_key)
$signature = $hmacsha.ComputeHash([Text.Encoding]::ASCII.GetBytes($sign))
$signature = [Convert]::ToBase64String($signature)
$header = #{
"CB-ACCESS-SIGN"=$signature
"CB-ACCESS-TIMESTAMP"=$epochtime
"CB-VERSION" = '2017-08-07'
"CB-ACCESS-KEY"='xxxxxxxxxxxxxx'
}
Invoke-WebRequest $accounts -Headers $header
Hopefully this will get you going. I just started working on a module today and got stuck on the same thing. I came across your question while trying to solve the problem myself. Figured I would share what I found. Good luck!
$accounts = 'https://api.coinbase.com/v2/accounts'
$time = 'https://api.coinbase.com/v2/time'
$epochtime = [string]((Invoke-WebRequest $time | ConvertFrom-Json).data).epoch
$method = 'GET'
$requestpath = '/v2/accounts'
$secret_key = (Get-CoinBaseAPIKeys).Secret
$sign = $epochtime + $method + $requestpath
$hmacsha = New-Object System.Security.Cryptography.HMACSHA256
$hmacsha.key = [Text.Encoding]::UTF8.GetBytes($secret_key)
$computeSha = $hmacsha.ComputeHash([Text.Encoding]::UTF8.GetBytes($sign))
The LONG WAY, for reference:
$signature = ""
foreach ( $c in $computeSha )
{
$signature += "{0:x2}" -f $c
}
The short way. Oddly I got stuck on this SAME issue, because the short way
produces UPPER CASE HEX and the long way ^^above^^ converts to lower case HEX.
The CoinBase API will ONLY accept the signature in HEX in lower case.
$signature = ([System.BitConverter]::ToString($computeSha) -replace "-").ToLower()
Now that we have the signature figured out, the rest should work great. I removed the CB_VERSION because it will default to your OWN API version. My default was different, so I simply removed it.
$header = #{
"CB-ACCESS-SIGN"=$signature
"CB-ACCESS-TIMESTAMP"=$epochtime
"CB-ACCESS-KEY"=(Get-CoinBaseAPIKeys).Key
}
$result = Invoke-WebRequest $accounts -Headers $header -Method Get -ContentType "application/json"
$accounts = $result.Content | ConvertFrom-Json
Write-Output $accounts.data
As an aside on storing PRIVATE KEY/SECRET you can find some ideas here:
https://github.com/cmaahs/BittrexAPI/tree/master/Encryption. Feel free to grab it and modify as you will. Better to store your KEY/SECRET encrypted in the registry rather than as plain text in your script or as environment variables.

Download SharePoint 2010 Library Items using PowerShell V2 with CSOM

my goal is: Get the items within the folders in a SharePoint 2010 library. I'm struggling trying to get some Items from a SharePoint 2010 Library using CSOM with PowerShell.
I tried three different methods that i found in the internet but still without success. Also the Microsoft's Documentation is really sh*t in this aspect, hope somebody can help me. So here we go:
1.Method A
[Microsoft.SharePoint.Client.FileInformation]$fileInfo = [Microsoft.SharePoint.Client.File]::OpenBinaryDirect($ctx, $file.ServerRelativeUrl);
[System.IO.FileStream]$writeStream = [System.IO.File]::Open("$($libraryTargetPath)\$($file.Name)", [System.IO.FileMode]::Create);
$fileInfo.Stream.CopyTo($writeStream);
$writeStream.Close();
With the A method I get this error:
Method invocation failed because [System.Net.ConnectStream] doesn't contain a method named 'CopyTo'.
+ $fileInfo.Stream.CopyTo <<<< ($writeStream);
+ CategoryInfo : InvalidOperation: (CopyTo:String) [], RuntimeException
+ FullyQualifiedErrorId : MethodNotFound
The [System.Net.ConnectStream] can't find the method CopyTo
I was lookign information about this, in the System.Net namespace and in the "Microsoft.SharePoint.Client.FileInformation" class but without success :(
2.Method B
$binary = [Microsoft.SharePoint.Client.File]::OpenBinaryDirect($ctx, $file.ServerRelativeUrl)
$Action = [System.IO.FileMode]::Create
$new = "$($libraryTargetPath)\$($file.Name)"
$stream = New-Object System.IO.FileStream $new, $Action
$writer = New-Object System.IO.BinaryWriter($stream)
$writer.write($binary)
$writer.Close()
Method B don't give me a error, but in stead of downloading the Items, it makes empty files in the destination folder. So this method isn't downloading the items, just making new files.
3.Method C
$binary = $file.OpenBinary()
$stream = New-Object System.IO.FileStream("$($libraryTargetPath)\$($file.Name)"), Create
$writer = New-Object System.IO.BinaryWriter($stream)
$writer.write($binary)
$writer.Close()
I'm not sure if method C belongs to CSOM or to the SharPoint built-in Server side client, if it's so please let me know. This is the error i'm getting:
Method invocation failed because [Microsoft.SharePoint.Client.File] doesn't contain a method named 'OpenBinary'.
At C:\Users\Administrator\Desktop\SharePointOnPremisesBackUp\SharePointOnPremisesBackUp.ps1:77 char:31
+ $binary = $file.OpenBinary <<<< ()
+ CategoryInfo : InvalidOperation: (OpenBinary:String) [], RuntimeException
+ FullyQualifiedErrorId : MethodNotFound
And here PowerShell can't find the OpenBinary() method in Microsoft.SharePoint.Client.File and there is nearly not information about this method.
Here is the complete function I'm trying to use:
function GetDocumentLibs ($ctx, $web)
{
Function IterateFoldersRecursively([Microsoft.SharePoint.Client.Folder]$folder, [Microsoft.SharePoint.Client.ClientContext]$ctx)
{
# make sure that the "Web.Context.Url" is the current web url
if ($web.Context.Url.StartsWith($SiteCollectionUrl) -eq $true)
{
$files = $folder.Files
$ctx.Load($folder.Files)
$ctx.Load($folder.Folders)
$ctx.ExecuteQuery()
foreach ($subFolder in $folder.Folders)
{
IterateFoldersRecursively $subFolder $ctx
}
# Check if folder Exist and Skip
$libraryTargetPath = "$($TargetPath)\$($folder.ServerRelativeUrl.Replace('/', '\'))"
New-Item -Path $libraryTargetPath -ItemType Directory -Force
foreach ($file in $files)
{
# Method 1
[Microsoft.SharePoint.Client.FileInformation]$fileInfo = [Microsoft.SharePoint.Client.File]::OpenBinaryDirect($ctx, $file.ServerRelativeUrl);
[System.IO.FileStream]$writeStream = [System.IO.File]::Open("$($libraryTargetPath)\$($file.Name)", [System.IO.FileMode]::Create);
$fileInfo.Stream.CopyTo($writeStream)
$writeStream.Close()
# Method 2
$binary = [Microsoft.SharePoint.Client.File]::OpenBinaryDirect($ctx, $file.ServerRelativeUrl)
$Action = [System.IO.FileMode]::Create
$new = "$($libraryTargetPath)\$($file.Name)"
$stream = New-Object System.IO.FileStream $new, $Action
$writer = New-Object System.IO.BinaryWriter($stream)
$writer.write($binary)
$writer.Close()
# Method 3
$binary = $file.OpenBinary()
$stream = New-Object System.IO.FileStream("$($libraryTargetPath)\$($file.Name)"), Create
$writer = New-Object System.IO.BinaryWriter($stream)
$writer.write($binary)
$writer.Close()
# delete folder
}
}
}
$folder = $web.GetFolderByServerRelativeUrl($web.ServerRelativeUrl)
$ctx.Load($folder)
$ctx.ExecuteQuery()
IterateFoldersRecursively $folder $ctx
}
the tools I'm using:
Sapien's PowerShell Studio
PowerShell V2 with CSOM
SharePoint 2010 OnPremises
Please if you have any Solution, Reference, Documentation or tutorial that can be useful tell me. Thanks in advance.
After a lot of research i found a solution and decide to use this method:
function GetDocumentLibs ($ctx, $web)
{
$site = $ctx.Site
$ctx.Load($site)
$ctx.ExecuteQuery()
$siteUrl = $site.Url
Function IterateFoldersRecursively([Microsoft.SharePoint.Client.Folder]$folder, [Microsoft.SharePoint.Client.ClientContext]$ctx)
{
if ($web.Context.Url.StartsWith($SiteCollectionUrl) -eq $true)
{
$files = $folder.Files
$ctx.Load($folder.Files)
$ctx.Load($folder.Folders)
$ctx.ExecuteQuery()
foreach ($subFolder in $folder.Folders)
{
IterateFoldersRecursively $subFolder $ctx
}
$targetPath = "$($TargetPath)\$($folder.ServerRelativeUrl.Replace('/', '\'))"
New-Item -Path $targetPath -ItemType Directory -Force
foreach ($file in $files)
{
$client = new-object System.Net.WebClient
$client.UseDefaultCredentials = $true
$client.DownloadFile("$($siteUrl)$($file.ServerRelativeUrl)", "$($targetPath)\$($file.Name)")
}
}
}
$folder = $web.GetFolderByServerRelativeUrl($web.ServerRelativeUrl)
$ctx.Load($folder)
$ctx.ExecuteQuery()
IterateFoldersRecursively $folder $ctx
}
Remember to implement some exception handling.
I hope this is helpful for somebody with the same problem.

How to query REST API

I am using this code below to deal with the REST API query for Adobe Analytics. I always get the message "something went wrong" which means that the first IF is not active.
include_once('/path/SimpleRestClient.php');
$username = 'XXXXX';
$secret = 'XXXXX';
$nonce = md5(uniqid(php_uname('n'), true));
$nonce_ts = date('c');
$digest = base64_encode(sha1($nonce.$nonce_ts.$secret));
$server = "https://api.omniture.com";
$path = "/admin/1.4/rest/";
$rc=new SimpleRestClient();
$rc->setOption(CURLOPT_HTTPHEADER, array("X-WSSE: UsernameToken Username=\"$username\", PasswordDigest=\"$digest\", Nonce=\"$nonce\", Created=\"$nonce_ts\""));
$query="?method=Company.GetTokenUsage";
$rc->getWebRequest($server.$path.$query);
if ($rc->getStatusCode()==200)
{
$response=$rc->getWebResponse();
var_dump($response);
}
else
{
echo "something went wrong\n";
var_dump($rc->getInfo());
}
The $rc->getStatusCode(); does not exit. I get '404' when I use this line :
print_r ($rc->getStatusCode());
After googling, I found https://marketing.adobe.com/developer/blog/how-to-start-with-the-omniture-rest-api-in-php. It uses API version of 1.3 instead of 1.4. By updating the
$path = "/admin/1.4/rest/";
to
$path = "/admin/1.3/rest/";
I was able to stop getting 404 errors in the browser.

Powershell Salesforce SOAP API SessionHeader Type Converion Issue

Hi I am having trouble setting the SessionHeaderValue. I am basing my code on c#.Net. The login works and I receive the serviceUrl and sessionId in the login result but I can't get the session Id set in the session header
Here is the code
$uri = "c:\installs\sforce.wsdl"
$username = "username"
$password = "password"
# Proxy
$service = New-WebServiceProxy -Uri $uri -Namespace sforce -UseDefaultCredential
# Login
$loginResult = $service.login($username, $password)
$service.Url = $loginResult.serverUrl
$service.SessionHeaderValue = New-Object sforce.SessionHeader
This is the error I get which is a bit odd.
Exception setting "SessionHeaderValue": "Cannot convert the "sforce.SessionHeader" value of type "sforce.SessionHeader" to type "sforce.SessionHeader"."
I have been playing with this for a few hours now and have run out of ideas.
Any help is appreciated.
Anthony
The real problem is that you can't reuse $service. Your instance of $service is only good for the login, and that's it. I think it's due to the way New-WebServiceProxy works. Check this little script out:
$uri = 'file://C:\projects\CRM\SalesForce\Integration\enterprise.xml'
$api = new-webserviceproxy -uri $uri -NameSpace SalesForce
$api.GetType().Module.Assembly.ManifestModule.ScopeName
$api = new-object SalesForce.SforceService.ScopeName
$api.GetType().Module.Assembly.ManifestModule
If you were to run this script, (of course you'd need to substitute your own WSDL), you'd see something like this (the DLLs are dynamic, so the names will be different):
mhgl0l5w.dll
vzecopaq.dll
Notice that not only are the object references for $api different, but the dynamic assembly that New-WebServiceProxy creates is different for each one, which isn't what you might expect. That's why your cast is failing; your objects with the same name are different because they come from different dynamic assemblies. I'm not sure why the behavior is this way - if it's a peculiarity of New-WebServiceProxy, or somehow in SalesForce's WSDL.
The solution is actually pretty simple. Recreate your service object off the namespace generated by New-WebServiceProxy like so:
$uri = "c:\installs\sforce.wsdl"
$username = "username"
$password = "password"
# Proxy
$service = New-WebServiceProxy -Uri $uri -Namespace sforce -UseDefaultCredential
# Login
$loginResult = $service.login($username, $password)
$service = New-Object sforce.SforceService
$service.Url = $loginResult.serverUrl
$service.SessionHeaderValue = New-Object sforce.SessionHeader
I found a webpage that implies the the $service.SessionHeaderValue instance should be created using something like:
$service.SessionHeaderValue = New-ObjectFromProxy -proxy $service -proxyAttributeName "SessionHeaderValue" -typeName "SessionHeader"
There was a definition for the New-ObjectFromProxy function in PowerShell + SOAP + AuthenticationInfoValue:
function New-ObjectFromProxy {
param($proxy, $proxyAttributeName, $typeName)
# Locate the assembly for $proxy
$attribute = $proxy | gm | where { $_.Name -eq $proxyAttributeName }
$str = "`$assembly = [" + $attribute.TypeName + "].assembly"
invoke-expression $str
# Instantiate an AuthenticationHeaderValue object.
$type = $assembly.getTypes() | where { $_.Name -eq $typeName }
return $assembly.CreateInstance($type)
}
I don't profess to be a powershell expert, but it appears the instance of the object that New-Object creates isn't really the same type that the proxy object is expecting. Confusingly, they do have the same name.
It's also worth noting that you cannot define a web service proxy twice for the same namespace. This is required for a flow where you need to go to SOAP API to login, then pass the session id to the metadata API to make your requests.
Compare:
$LoginResponse = $sf.login($username, $password)
$newSession = $LoginResponse.sessionId
$newURL = $LoginResponse.serverUrl
$service = New-Object sforce.SforceService
$service.Url = $LoginResponse.serverUrl
$service.SessionHeaderValue = New-Object sforce.SessionHeader
$service.SessionHeaderValue.sessionId = $LoginResponse.sessionId
# Set the batch size to 2000
# Though, if it contains two long text area fields, it will set it as 200
# This is to avoid long SOAP messages and is controlled by SF
$service.QueryOptionsValue = new-Object sforce.QueryOptions
$service.QueryOptionsValue.batchSize = 2000
$service.QueryOptionsValue.batchSizeSpecified = $true
$mdservice= new-WebServiceProxy -URI $mdwsdl -Namespace sforce
$mdservice = New-Object sforce.MetadataService
$mdservice.Url = $LoginResponse.metadataServerUrl
$mdservice.SessionHeaderValue = New-Object sforce.SessionHeader
$mdservice.SessionHeaderValue.sessionId = $LoginResponse.sessionId
This will generate the following error:
"sforce.SessionHeader" to type "sforce.SessionHeader"."
At line:22 char:5
+ $mdservice.SessionHeaderValue = New-Object sforce.SessionHeader
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ CategoryInfo : NotSpecified: (:) [], SetValueInvocationException
+ FullyQualifiedErrorId : ExceptionWhenSetting
The property 'sessionId' cannot be found on this object. Verify that the property exists and can be set.
At line:23 char:5
+ $mdservice.SessionHeaderValue.sessionId = $LoginResponse.sessionI ...
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ CategoryInfo : InvalidOperation: (:) [], RuntimeException
+ FullyQualifiedErrorId : PropertyNotFound
Whereas the below code will not error:
$sf = new-WebServiceProxy -URI $pwsdl -Namespace sforce
$LoginResponse = $sf.login($username, $password)
$newSession = $LoginResponse.sessionId
$newURL = $LoginResponse.serverUrl
$service = New-Object sforce.SforceService
$service.Url = $LoginResponse.serverUrl
$service.SessionHeaderValue = New-Object sforce.SessionHeader
$service.SessionHeaderValue.sessionId = $LoginResponse.sessionId
# Set the batch size to 2000
# Though, if it contains two long text area fields, it will set it as 200
# This is to avoid long SOAP messages and is controlled by SF
$service.QueryOptionsValue = new-Object sforce.QueryOptions
$service.QueryOptionsValue.batchSize = 2000
$service.QueryOptionsValue.batchSizeSpecified = $true
$mdservice= new-WebServiceProxy -URI $mdwsdl #Don't set namespace here
# Notice that we are getting the namespace dynamically
$type = $mdservice.GetType().NameSpace
$mdservice = New-Object ($type + '.MetadataService')
$mdservice.Url = $LoginResponse.metadataServerUrl
$mdservice.SessionHeaderValue = New-Object ($type + '.SessionHeader')
$mdservice.SessionHeaderValue.sessionId = $LoginResponse.sessionId
Exception setting "SessionHeaderValue": "Cannot convert the "sforce.SessionHeader" value of type "sforce.SessionHeader" to type "sforce.SessionHeader"."
$service.SessionHeaderValue = New-Object sforce.SessionHeader
After New-Object you have to specify the correct class name. Try this:
#Login to Salesforce
$loginResults = $service.login($username,$password)
#set the session Id in partner Object
$service.Url = $loginResults.serverUrl
$sessionHeaderObjClassName = ($service.GetType().FullName) -replace "SforceService","SessionHeader"
$service.SessionHeaderValue = New-Object $sessionHeaderObjClassName
$service.SessionHeaderValue.sessionId = $loginResults.sessionId