Powershell .NET httpclient add header - powershell

I want to upload a file using powershell to a RestAPI. Sadly the invoke-restmethod does not support MultipartForm Uploads and even with building my own body it does not work. Therefore, I have to get this working using another way :)
Luckily I found this excellent blog post: http://blog.majcica.com/2016/01/13/powershell-tips-and-tricks-multipartform-data-requests/ and now I'm trying to build me a request using the .NET Client within Powershell. But I do hit my borders right now. I need to edit the standard header to add an authorization token. And I have no clue how! Would somebody please so kind and point me in the right direction how to do this? Thank you very much!
function Invoke-MultipartFormDataUpload
{
[CmdletBinding()]
PARAM
(
[string][parameter(Mandatory = $true)][ValidateNotNullOrEmpty()]$InFile,
[string]$ContentType,
[Uri][parameter(Mandatory = $true)][ValidateNotNullOrEmpty()]$Uri,
[System.Management.Automation.PSCredential]$Credential
)
BEGIN
{
if (-not (Test-Path $InFile))
{
$errorMessage = ("File {0} missing or unable to read." -f $InFile)
$exception = New-Object System.Exception $errorMessage
$errorRecord = New-Object System.Management.Automation.ErrorRecord $exception, 'MultipartFormDataUpload', ([System.Management.Automation.ErrorCategory]::InvalidArgument), $InFile
$PSCmdlet.ThrowTerminatingError($errorRecord)
}
if (-not $ContentType)
{
Add-Type -AssemblyName System.Web
$mimeType = [System.Web.MimeMapping]::GetMimeMapping($InFile)
if ($mimeType)
{
$ContentType = $mimeType
}
else
{
$ContentType = "application/octet-stream"
}
}
}
PROCESS
{
Add-Type -AssemblyName System.Net.Http
$httpClientHandler = New-Object System.Net.Http.HttpClientHandler
if ($Credential)
{
$networkCredential = New-Object System.Net.NetworkCredential #($Credential.UserName, $Credential.Password)
$httpClientHandler.Credentials = $networkCredential
}
$httpClient = New-Object System.Net.Http.Httpclient $httpClientHandler
$packageFileStream = New-Object System.IO.FileStream #($InFile, [System.IO.FileMode]::Open)
$contentDispositionHeaderValue = New-Object System.Net.Http.Headers.ContentDispositionHeaderValue "form-data"
$contentDispositionHeaderValue.Name = "fileData"
$contentDispositionHeaderValue.FileName = (Split-Path $InFile -leaf)
$streamContent = New-Object System.Net.Http.StreamContent $packageFileStream
$streamContent.Headers.ContentDisposition = $contentDispositionHeaderValue
$streamContent.Headers.ContentType = New-Object System.Net.Http.Headers.MediaTypeHeaderValue $ContentType
$content = New-Object System.Net.Http.MultipartFormDataContent
$content.Add($streamContent)
try
{
$response = $httpClient.PostAsync($Uri, $content).Result
if (!$response.IsSuccessStatusCode)
{
$responseBody = $response.Content.ReadAsStringAsync().Result
$errorMessage = "Status code {0}. Reason {1}. Server reported the following message: {2}." -f $response.StatusCode, $response.ReasonPhrase, $responseBody
throw [System.Net.Http.HttpRequestException] $errorMessage
}
return $response.Content.ReadAsStringAsync().Result
}
catch [Exception]
{
$PSCmdlet.ThrowTerminatingError($_)
}
finally
{
if($null -ne $httpClient)
{
$httpClient.Dispose()
}
if($null -ne $response)
{
$response.Dispose()
}
}
}
END { }
}

Try this
#Authorization
$httpClient.DefaultRequestHeaders.Authorization = New-Object System.Net.Http.Headers.AuthenticationHeaderValue("Bearer", $accesstoken);

Related

itextsharp - stamp AND add additional page

I already have a working snippet for stamping PDF's.
But, now a request has reached me for adding an additional page to the same document.
I have managed to get it working, but I'd like to verify that it is the best way to do it.
Edit: It turns out it is not working as expected.
The fields get malformatted with a big "x" instead of the text as per below image. If I click the field I can see that the text has been input though.
Old code
$FieldsHash = ConvertFrom-StringData -StringData $Fields
$FieldsHash | Export-Clixml C:\Temp\fieldhash.xml
$reader = New-Object iTextSharp.text.pdf.PdfReader -ArgumentList $InputPdfFilePath
$stamper = New-Object iTextSharp.text.pdf.PdfStamper($reader, [System.IO.File]::Create($OutputPdfFilePath))
foreach ($j in $FieldsHash.GetEnumerator())
{
try {
$formattedDate = Get-Date $j.Value -Format $DatePattern
$null = $stamper.AcroFields.SetField($j.Key, $formattedDate)
}
catch {
try {
$null = $stamper.AcroFields.SetField($j.Key, $j.Value)
} catch {
"Could not find $($j.Key)"
}
}
}
$stamper.Close()
Modified code:
$fileStream = New-Object System.IO.FileStream($OutputPdfFilePath, [System.IO.FileMode]::OpenOrCreate)
$document = New-Object iTextSharp.text.Document
$pdfCopy = New-Object iTextSharp.text.pdf.PdfCopy($document, $fileStream)
$mainreader = New-Object iTextSharp.text.pdf.PdfReader($InputPdfFilePath)
$stamper = New-Object iTextSharp.text.pdf.PdfStamper($mainreader, $fileStream)
$document.Open()
$FieldsHash = ConvertFrom-StringData -StringData $Fields
$FieldsHash | Export-Clixml C:\Temp\pdf\fieldhash.xml
foreach ($j in $FieldsHash.GetEnumerator())
{
try {
$formattedDate = Get-Date $j.Value -Format $DatePattern
$null = $stamper.AcroFields.SetField($j.Key, $formattedDate)
} catch {
try {
$null = $stamper.AcroFields.SetField($j.Key, $j.Value)
} catch {
"Could not find $($j.Key)"
}
}
}
$pdfCopy.AddDocument($mainreader)
$mainreader.Dispose()
$attreader = New-Object iTextSharp.text.pdf.PdfReader($att)
$pdfCopy.AddDocument($attreader)
$attreader.Dispose()
$pdfCopy.Dispose()
$document.Dispose()
$fileStream.Dispose()
Solution, user stamper methods instead:
$reader = New-Object iTextSharp.text.pdf.PdfReader -ArgumentList $InputPdfFilePath
$stamper = New-Object iTextSharp.text.pdf.PdfStamper($reader, [System.IO.File]::Create($OutputPdfFilePath))
foreach ($j in $FieldsHash.GetEnumerator())
{
try {
$formattedDate = Get-Date $j.Value -Format $DatePattern
$null = $stamper.AcroFields.SetField($j.Key, $formattedDate)
} catch {
try {
$null = $stamper.AcroFields.SetField($j.Key, $j.Value)
} catch {
"Could not find $($j.Key)"
}
}
}
if(Test-Path $attpath) {
$attreader = New-Object iTextSharp.text.pdf.PdfReader($attpath)
$stamper.InsertPage(3,$attreader.GetPageSize(1))
$stamper.replacePage($attreader, 1, 3)
$stamper.Close()
$reader.Close()
$attreader.Close()
}
else {
$stamper.Close()
$reader.Close()
}

Check if password-protected web file exists

I need to check to see if a password-protected web file exists in a directory.
I keep getting a (401) Unauthorized error so, Lines 5-6 are not working.
Script Code:
$currdate = Get-Date -format "yyyyMMdd"
$Username = "username"
$Password = "password"
$url = "http://some.website/" + $currdate + "/somedirectory/some.file.txt"
$WebClient = New-Object System.Net.WebClient
$WebClient.Credentials = New-Object System.Net.Networkcredential($Username, $Password)
$HTTP_Request = [System.Net.WebRequest]::Create($url)
$HTTP_Response = $HTTP_Request.GetResponse()
$HTTP_Status = [int]$HTTP_Response.StatusCode
If ($HTTP_Status -eq 200) {
Write-Host "File exists!"
}
Else {
Write-Host "File does not exist..."
}
$HTTP_Response.Close()
What am I doing wrong?
You use two objects WebClient and WebRequest, you need only one.
You set the credential to WebClient, but you do response by WebRequest without credential.
Modify your code as:
$currdate = Get-Date -format "yyyyMMdd"
$Username = "xxxxx"
$Password = "xxxxxx"
$url = "http://some.website/" + $currdate + "/somedirectory/some.file.txt"
# comment these lines,you use WebRequest
#$WebClient = New-Object System.Net.WebClient
#$WebClient.Credentials = New-Object System.Net.Networkcredential($Username, $Password)
$HTTP_Request = [System.Net.WebRequest]::Create($url)
#add this line
$HTTP_Request.Credentials = new-object system.net.networkcredential($Username, $Password)
$HTTP_Response = $HTTP_Request.GetResponse()
$HTTP_Status = [int]$HTTP_Response.StatusCode
If ($HTTP_Status -eq 200) {
Write-Host "File exists!"
}
Else {
Write-Host "File does not exist..."
}
$HTTP_Response.Close()

PowerShell calling Sharepoint 2013 REST API update list item

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

Powershell Http post request

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

How to post a tweet to twitter using Powershell?

Has anyone used the following code? How do I make it post a tweet? I know I have to use the "$req.Context.RawUri = [Uri]'http://api.twitter.com/version/statuses/update.xml" but I can't get the "$res = [xml][DevDefined.OAuth.Consumer.ConsumerRequestExtensions]::ReadBody($req)" right.
Add-Type -Path C:\OAuthDevDefined\DevDefined.OAuth.dll
$cons = New-Object devdefined.oauth.consumer.oauthconsumercontext
$cons.ConsumerKey = 'key'
$cons.ConsumerSecret = 'key'
$cons.SignatureMethod = [devdefined.oauth.framework.signaturemethod]::HmacSha1
$session = new-object DevDefined.OAuth.Consumer.OAuthSession $cons, $null, $null, $null
$accessToken = new-object DevDefined.OAuth.Framework.TokenBase
$at = import-cliXml C:\temp\myTwitterAccessToken.clixml
$accessToken.ConsumerKey, $accessToken.Realm, $accessToken.Token, $accessToken.TokenSecret = `
$at.ConsumerKey, $at.Realm, $at.Token, $at.TokenSecret
$req = $session.Request($accessToken)
$req.Context.RequestMethod = 'GET'
$req.Context.RawUri = [Uri]'http://api.twitter.com/1/statuses/friends_timeline.xml?count=5'
$res = [xml][DevDefined.OAuth.Consumer.ConsumerRequestExtensions]::ReadBody($req)
$res.statuses.status | % { $_.user.Name }
I use OAuth by DevDefined as well. My function looks like this:
function Post-Twitter {
param(
[Parameter(Mandatory=$true)][string]$url
)
if (!$script:accessToken) {
throw 'token is not initialized'
}
try {
$cons = New-Object devdefined.oauth.consumer.oauthconsumercontext
$cons.ConsumerKey = $consumerKey
$cons.ConsumerSecret = $consumerSecret
$cons.SignatureMethod = [devdefined.oauth.framework.signaturemethod]::HmacSha1
$session = new-object DevDefined.OAuth.Consumer.OAuthSession `
$cons,
"http://twitter.com/oauth/request_token",
"http://twitter.com/oauth/authorize",
"http://twitter.com/oauth/access_token"
$token = Get-AccessToken
$req = $session.Request($token)
$req.Context.RequestMethod = 'POST'
$req.Context.RawUri = new-object Uri $url
[DevDefined.OAuth.Consumer.ConsumerRequestExtensions]::ReadBody($req)
} catch {
Write-Warning "Exception: $_"
$null
}
}
Then for simplicity I pass status in query string:
add-type -assembly System.Web
$status = [system.Web.Httputility]::UrlEncode('some tweet')
Post-Twitter "http://api.twitter.com/1/statuses/update.xml?status=$status"
It seems that you know about the consumer key/secret and the token thing, so I'll leave it without further explanation.
I’ve just posted a Powershell Twitter REST API 1.1 Module on TechNet Gallery… You'll be able to post/get from Twitter API! https://goo.gl/s7pmmA