An adaptation of Vadim's answers to Upload file to SharePoint 2010 using PowerShell and the OData API and SharePoint 2010 REST API JQUery Insert, Update, Delete.
Attempting to upload a new version of an attachment:
Function Update-Attachments() {
[CmdletBinding()]
Param(
[Parameter(Mandatory=$True,Position=1)]
[string]$WebUrl,
[Parameter(Mandatory=$True,Position=2)]
[string]$ListName,
[Parameter(Mandatory=$True,Position=3)]
[int]$ItemId,
# pipeline support
[Parameter(Mandatory=$True,Position=4,ValueFromPipeline=$True,ValueFromPipelineByPropertyName=$True)]
# associate FileInfo object's FullName property to be bound to parameter
[Alias('FullName')]
[string[]]$Paths
)
BEGIN {}
PROCESS {
#
$endpointUri = New-Object System.Uri("$WebUrl/_vti_bin/listdata.svc/$ListName($ItemId)/Attachments")
Foreach ($Path In $Paths) {
Write-Verbose "Path: $Path"
$fileName = (Split-Path $Path -Leaf)
$fileContent = ([IO.File]::ReadAllBytes($Path))
$headers = #{
"X-HTTP-Method" = "MERGE";
"If-Match" = "*"
}
try {
# reset each pass to ensure that prior response isn't reused
$response=$null
$response = Invoke-WebRequest -Uri $endpointUri -Method POST -UseDefaultCredentials -Body $fileContent -Headers $headers -ContentType "*/*"
}
# Invoke-WebRequest throws System.Net.WebException
catch [System.Net.WebException] {
throw $_
}
finally {
# returns Microsoft.PowerShell.Commands.HtmlWebResponseObject
$response
}
} # Foreach
} # PROCESS
END {}
}
Using the command throws (405) Method Not Allowed:
Update-Attachments -WebUrl "http://contoso.intranet.com/" -ListName "Tasks" -ItemId 1 -Paths "C:\Users\user\Documents\SharePointUserGuide.docx"
I've tried variations on the endpoint:
$endpointUri = New-Object System.Uri("$WebUrl/_vti_bin/listdata.svc/$ListName/Attachments/$ItemId/$fileName")
$endpointUri = New-Object System.Uri("$WebUrl/_vti_bin/listdata.svc/Attachments(EntitySet='$ListName',ItemId=$ItemId,Name='$fileName')")
and switching between PUT and MERGE.
What am I missing?
Can you check whether this SharePoint 2013 reference works with the 2010 API?
url: http://site url/_api/web/lists/getbytitle('list title')/items(item id)/AttachmentFiles('file name')/$value
method: POST
body: "Contents of file."
headers:
Authorization: "Bearer " + accessToken
"X-HTTP-Method":"PUT"
X-RequestDigest: form digest value
content-length:length of post body
https://msdn.microsoft.com/en-us/library/office/dn292553.aspx?f=255&MSPPError=-2147217396
Related
$API_KEY = "xxxxxxxxxx"
# Source image files
$ImageFiles = (Get-ChildItem -Path C:\Users\sam\Desktop\jpeg\* -filter *).Name
$uploadedFiles = #()
try {
foreach ($imageFile in $ImageFiles ) {
# 1a. RETRIEVE THE PRESIGNED URL TO UPLOAD THE FILE.
# Prepare URL for `Get Presigned URL` API call
$query = "https://api.pdf.co/v1/file/upload/get-presigned-url?
contenttype=application/octet-stream&name=" + `
[IO.Path]::GetFileName($imageFile)
$query = [System.Uri]::EscapeUriString($query)
# Execute request
$jsonResponse = Invoke-RestMethod -Method Get -Headers #{ "x-api-key" = $API_KEY } -Uri
$query
if ($jsonResponse.error -eq $false) {
# Get URL to use for the file upload
$uploadUrl = $jsonResponse.presignedUrl
# Get URL of uploaded file to use with later API calls
$uploadedFileUrl = $jsonResponse.url
# 1b. UPLOAD THE FILE TO CLOUD.
$r = Invoke-WebRequest -Method Put -Headers #{ "x-api-key" = $API_KEY; "content-type"
= "application/octet-stream" } -InFile $imageFile -Uri $uploadUrl
if ($r.StatusCode -eq 200) {
# Keep uploaded file URL
$uploadedFiles += $uploadedFileUrl
}
else {
# Display request error status
Write-Host $r.StatusCode + " " + $r.StatusDescription
}
}
else {
# Display service reported error
Write-Host $jsonResponse.message
}
}
if ($uploadedFiles.length -gt 0) {
# 2. CREATE PDF DOCUMENT FROM UPLOADED IMAGE FILES
# Prepare URL for `DOC To PDF` API call
$query = "https://api.pdf.co/v1/pdf/convert/from/image"
# Prepare request body (will be auto-converted to JSON by Invoke-RestMethod)
# See documentation: https://apidocs.pdf.co
$body = #{
"name" = $(Split-Path $DestinationFile -Leaf)
"url" = $uploadedFiles -join ","
} | ConvertTo-Json
# Execute request
$response = Invoke-WebRequest -Method Post -Headers #{ "x-api-key" = $API_KEY; "Content-
Type" = "application/json" } -Body $body -Uri $query
$jsonResponse = $response.Content | ConvertFrom-Json
if ($jsonResponse.error -eq $false) {
# Get URL of generated PDF file
$resultFileUrl = $jsonResponse.url;
$DestinationFile = "C:\Users\sam\Desktop\pdf\$imagefile.split('.')[0]"
# Download PDF file
Invoke-WebRequest -Headers #{ "x-api-key" = $API_KEY } -OutFile $DestinationFile -Uri
$resultFileUrl
Write-Host "Generated PDF file saved as `"$($DestinationFile)`" file."
}
else {
# Display service reported error
Write-Host $jsonResponse.message
}
}
}
catch {
# Display request error
Write-Host $_.Exception
}
Basically this script converts bulk number of JPEG images to PDF format .Its working initially but later when i execute the script it is getting failed by this error "The underlying connection was closed: An unexpected error occurred on a send." . I googled this issue and added these two lines at the beginning of the script –
#[Net.ServicePointManager]::SecurityProtocolNet.SecurityProtocolType]::Tls12 [Net.ServicePointManager]::SecurityProtocol = [Net.SecurityProtocolType]::Tls -bor [Net.SecurityProtocolType]::Tls11 -bor [Net.SecurityProtocolType]::Tls12 .
Even after adding these two am getting the same old error .Can anyone please help me with this issue
I am trying to work out a powershell script that:
retrieves an accesstoken (MSAL) to access (read/write) a sharepoint online site with subsites and documents. Preferably the Azure APP-registration ServicePrincipal can be granted access to just that site and access the sharepoint site/files without giving consent to the whole sharepoint environment. I don't know if that is possible currently as I can only grant application permission to files.readwrite.all and sites.readwrite.all. I do not see anything like files.readwrite.shared to grant access only to sites/collections that the serviceprincipal has access to. Anyone done this? I currently use the MSAL.PS powershell module to get a token using an AppRegistration with the admin-consented readwrite.all access but would like to limit that. The code for this is now:
Import-Module MSAL.PS;
$clientid = "my-appreg-client-id";
$tenantID = 'my-tenant-id';
$thumbPrint = 'certificate-thumbprint';
$ClientCertificate = Get-Item "Cert:\CurrentUser\My\$thumbPrint";
$myAccessToken = Get-MsalToken -ClientId $clientID -TenantId $tenantID -ClientCertificate
$ClientCertificate;
The script will read all files and folders from an UNC-share and build a file-collection of the onprem files. That part of the code is in place using a Get-ChildItem call to the UNC filetree.
Then, after getting the token, I need to get the current available files in the sharepoint online site document library structure and store that in a variable/hashtable which I can use to perform lookups between the onprem filecollection and the presence of those files and (sub)folders in the sharepoint site. If a folder does not yet exist I need to create that sharepoint folder and if a file is not yet present or the onprem version is newer I need to upload that file into sharepoint.
I have a script that does this using the old sharepoint.client.dll libraries but those support only basic authentication which will be unavailable any time soon for accessing the MS Online environment. So now I am searching for code to do this using the Microsoft Graph Api or other Rest API call. I am already struggling to get the contents of a site file collection so I hope that this generic problem description is enough to get some hints and tips/resources to get going.
Many thanks,
Eric
This is what I use. I'm using powershell in Linux.
## Get the Token
$clientId = "Application (Client) ID"
$clientSecret = "Client secret"
$tenantName = "TenantName.onmicrosoft.com"
$tokenBody = #{
Grant_Type = 'client_credentials'
Scope = 'https://graph.microsoft.com/.default'
Client_Id = $clientId
Client_Secret = $clientSecret
}
$tokenResponse = Invoke-RestMethod -Uri "https://login.microsoftonline.com/$TenantName/oauth2/v2.0/token" -Method POST -Body $tokenBody -ErrorAction Stop
$headers = #{
"Authorization" = "Bearer $($tokenResponse.access_token)"
"Content-Type" = "application/json"
}
## Use the SharePoint groups ObjectID. From this we'll get the drive ID.
$site_objectid = "Groups ObjectID"
## Create all the folders on the SharePoint site first. I've set microsoft.graph.conflictBehavior below to fail because I never want to rename or replace folders.
# Set the base directory.
$baseDirectory = "/test"
$directories = get-childItem -path $baseDirectory -recurse -directory
foreach ($directory in $directories) {
$URL = "https://graph.microsoft.com/v1.0/groups/$site_objectid/sites/root"
$subsite_ID = (Invoke-RestMethod -Headers $headers -Uri $URL -Method Get).ID
$URL = "https://graph.microsoft.com/v1.0/sites/$subsite_ID/drives"
$Drives = Invoke-RestMethod -Headers $headers -Uri $URL -Method Get
$Document_drive_ID = ($Drives.value | Where-Object { $_.name -eq 'Documents' }).id
$createFolderURL = "https://graph.microsoft.com/v1.0/drives/$Document_drive_ID/items/root:{0}:/children" -f $directory.parent.FullName
$file = $directory.Name
$uploadFolderRequestBody = #{
name= "$file"
folder = #{}
"#microsoft.graph.conflictBehavior"= "fail"
} | ConvertTo-Json
invoke-restMethod -headers $headers -method Post -body $uploadFolderRequestBody -contentType "application/json" -uri $createFolderURL
}
## Upload the files. I'm only adding files that are 4 days old or less because I run the script every 3 days for backup.
## These are set in the $sharefiles variable. To upload all files just remove everything after the pipe.
$sharefiles = get-childItem $baseDirectory -recurse | Where-Object {$_.LastWriteTime -gt (Get-Date).AddDays(-4)}
foreach ($sharefile in $sharefiles) {
$Filepath = $sharefile.FullName
$URL = "https://graph.microsoft.com/v1.0/groups/$site_objectid/sites/root"
$subsite_ID = (Invoke-RestMethod -Headers $headers -Uri $URL -Method Get).ID
$URL = "https://graph.microsoft.com/v1.0/sites/$subsite_ID/drives"
$Drives = Invoke-RestMethod -Headers $headers -Uri $URL -Method Get
$Document_drive_ID = ($Drives.value | Where-Object { $_.name -eq 'Documents' }).id
$Filename = $sharefile.Name
$upload_session = "https://graph.microsoft.com/v1.0/drives/$Document_drive_ID/root:{0}/$($Filename):/createUploadSession" -f $sharefile.directory.FullName
$upload_session_url = (Invoke-RestMethod -Uri $upload_session -Headers $headers -Method Post).uploadUrl
## We'll upload files in chunks.
$ChunkSize = 62259200
$file = New-Object System.IO.FileInfo($Filepath)
$reader = [System.IO.File]::OpenRead($Filepath)
$buffer = New-Object -TypeName Byte[] -ArgumentList $ChunkSize
$position = 0
$counter = 0
Write-Host "ChunkSize: $ChunkSize" -ForegroundColor Cyan
Write-Host "BufferSize: $($buffer.Length)" -ForegroundColor Cyan
$moreData = $true
While ($moreData) {
#Read a chunk
$bytesRead = $reader.Read($buffer, 0, $buffer.Length)
$output = $buffer
If ($bytesRead -ne $buffer.Length) {
#no more data to be read
$moreData = $false
#shrink the output array to the number of bytes
$output = New-Object -TypeName Byte[] -ArgumentList $bytesRead
[Array]::Copy($buffer, $output, $bytesRead)
Write-Host "no more data" -ForegroundColor Yellow
}
#Upload the chunk
$Header = #{
'Content-Range' = "bytes $position-$($position + $output.Length - 1)/$($file.Length)"
}
Write-Host "Content-Range = bytes $position-$($position + $output.Length - 1)/$($file.Length)" -ForegroundColor Cyan
#$position = $position + $output.Length - 1
$position = $position + $output.Length
Invoke-RestMethod -Method Put -Uri $upload_session_url -Body $output -Headers $Header -SkipHeaderValidation
#Increment counter
$counter++
}
$reader.Close()
}
I want to be able to load SharePoint Online pages with Invoke-Webrequest from Powershell.
Can someone please show me how to successfully navigate past the login screen?
Here is how I get list items from SPO. You need to have "Microsoft.SharePoint.Client.SharePointOnlineCredentials" dll.
Then use the below function that I have modified for SPO.
Advantage: This will even work with older PowerShell versions. If you want to target only higher level of PowerShell then also this code will work. Optionally you can use Invoke-Webrequest instead of System.Net.HttpWebRequest and System.Net.HttpWebResponse.
function Get-ListItems {
[CmdletBinding()]
PARAM (
[Parameter(Mandatory=$true)]
[String] $URL
)
#$URL = Fix-Url $URL
$xml = Request-Rest -URL $URL
return $xml
}
function Request-Rest{
[CmdletBinding()]
PARAM (
[Parameter(Mandatory=$true)]
[String] $URL,
[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.
$URI = New-Object System.Uri($URL,$true)
#Create a request object using the URI
$request = [System.Net.HttpWebRequest]::Create($URI)
#Build up a nice 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
}
if ($PSBoundParameters.ContainsKey('JSON'))
{
$request.Accept = "application/json"
}
$request.Headers.Add("X-FORMS_BASED_AUTH_ACCEPTED", "f")
#$request.Accept = "application/json;odata=verbose"
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
{
[xml]$output = $reader.ReadToEnd()
}
$reader.Close()
Write-Output $output
$response.Close()
}
Though I do not know the direct way to pass the credentials along with Invoke-WebRequest itself, one workaround I found is, capture the cookie values by manual authenticating the SharePoint page and use those for subsequent requests. You can use fiddler or some other similar tool to grab the cookies. The two cookie names were 'FedAuth' and 'rtFa'
$session = New-Object Microsoft.PowerShell.Commands.WebRequestSession
$cookieCollection = New-Object System.Net.CookieCollection
$cookie1 = New-Object System.Net.Cookie
$cookie1.Domain = "<your domain>.sharepoint.com"
$cookie1.Name = "FedAuth"
$cookie1.Value = "<cookie value here>"
$cookieCollection.Add($cookie1)
$cookie2 = New-Object System.Net.Cookie
$cookie2.Domain = "<your domain>.sharepoint.com"
$cookie2.Name = "rtFa"
$cookie2.Value = "<cookie value here>"
$cookieCollection.Add($cookie2)
$session.Cookies.Add($cookieCollection)
$uri = "https:<your site collection here>/_layouts/15/SharePointDesignerSettings.aspx"
$response = Invoke-WebRequest -Uri $uri -WebSession $session -Method Default
$form = $response.Forms[0]
You can use $form to examine the Html elements. If you want to submit the changes made to form use the below line
$response = Invoke-WebRequest -Uri $uri -WebSession $session -Method POST -Body $form
Note: There is an issue with Invoke-WebRequest with respect to field submission.. basically it uses 'id' of input element instead of 'name' in form fields collection.. the below url has the code to convert field Id to Name
https://d-fens.ch/2013/05/11/invoke-webrequest-uses-id-attribute-of-input-element-as-field-name-in-form-fields-collection/
If you are looking for the final content of a page, Invoke-WebRequest will not do what you need. Much of the content of a SharePoint page is loaded asynchronously using JavaScript. Invoke-WebRequest will only return the initial HTML content from the page.
What kind of content are you looking for from the page? Most everything about SharePoint can be accessed using RESTful queries (Invoke-RESTMethod and the SharePoint REST API) or from the PowerShell SharePoint PNP and SharePoint Online cmdlet libraries.
What I am currently doing:
Invoke-WebRequest -Uri https://coolWebsite.com/ext/ext -ContentType application/json -Method POST -Body $someJSONFile
I am looking for a way to POST this same .json file in Powershell without using Invoke-WebRequest, if it is possible. This new method would preferably allow me to get the server output content and parse through it in powershell.
Maybe by calling an outside cURL method? I really am not sure and all my internet research has proved fruitless.
How can I achieve this above result without Invoke-WebRequest?
You can try this :
# RestRequest.ps1
Add-Type -AssemblyName System.ServiceModel.Web, System.Runtime.Serialization, System.Web.Extensions
$utf8 = [System.Text.Encoding]::UTF8
function Request-Rest
{
[CmdletBinding()]
PARAM (
[Parameter(Mandatory=$true)]
[String] $URL,
[Parameter(Mandatory=$false)]
[System.Net.NetworkCredential] $credentials,
[Parameter(Mandatory=$true)]
[String] $JSON)
# Remove NewLine from json
$JSON = $JSON -replace "$([Environment]::NewLine) *",""
# Create a URL instance since the HttpWebRequest.Create Method will escape the URL by default.
# $URL = Fix-Url $Url
$URI = New-Object System.Uri($URL,$true)
try
{
# Create a request object using the URI
$request = [System.Net.HttpWebRequest]::Create($URI)
# Build up a nice User Agent
$UserAgent = "My 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"))
$request.Credentials = $credentials
$request.KeepAlive = $true
$request.Pipelined = $true
$request.AllowAutoRedirect = $false
$request.Method = "POST"
$request.ContentType = "application/json"
$request.Accept = "application/json"
$utf8Bytes = [System.Text.Encoding]::UTF8.GetBytes($JSON)
$request.ContentLength = $utf8Bytes.Length
$postStream = $request.GetRequestStream()
$postStream.Write($utf8Bytes, 0, $utf8Bytes.Length)
#Write-String -stream $postStream -string $JSON
$postStream.Dispose()
try
{
#[System.Net.HttpWebResponse] $response = [System.Net.HttpWebResponse] $request.GetResponse()
$response = $request.GetResponse()
}
catch
{
$response = $Error[0].Exception.InnerException.Response;
Throw "Exception occurred in $($MyInvocation.MyCommand): `n$($_.Exception.Message)"
}
$reader = [IO.StreamReader] $response.GetResponseStream()
$output = $reader.ReadToEnd()
$reader.Close()
$response.Close()
Write-Output $output
}
catch
{
$output = #"
{
"error":1,
"error_desc":"Error : Problème d'accès au serveur $($_.Exception.Message)"
}
"#
Write-Output $output
}
}
Edited 19-10-2015
Here is an example usage :
#$urlBase = "http://192.168.1.1:8080/"
#######################################################################
# Login #
#######################################################################
$wsLogin = "production/login"
Function login
{
[CmdletBinding()]
PARAM
(
[ValidateNotNullOrEmpty()]
[String] $login,
[String] $passwd
)
Write-Verbose $wsLogin
#$jsonIn = [PSCustomObject]#{"login"=$login;"passwd"=$passwd} | ConvertTo-Json
$jsonIn = #"
{
"login":"$login",
"passwd":"$passwd"
}
"#
Write-Verbose $jsonIn
$jsonOut = Request-Rest -URL "$urlBase$wsLogin" -JSON $jsonIn -credentials $null
Write-Verbose $jsonOut
#return $jsonOut | ConvertFrom-Json
return $jsonOut
}
It is easy to convert that code to cURL
curl -v --insecure -X POST -H "Content-Type: application/json" --data-binary someJSONFile.js https://coolWebsite.com/ext/ext/
I'm trying to send a file via Invoke-RestMethod in a similar context as curl with the -F switch.
Curl Example
curl -F FileName=#"/path-to-file.name" "https://uri-to-post"
In powershell, I've tried something like this:
$uri = "https://uri-to-post"
$contentType = "multipart/form-data"
$body = #{
"FileName" = Get-Content($filePath) -Raw
}
Invoke-WebRequest -Uri $uri -Method Post -ContentType $contentType -Body $body
}
If I check fiddler I see that the body contains the raw binary data, but I get a 200 response back showing no payload has been sent.
I've also tried to use the -InFile parameter with no luck.
I've seen a number of examples using a .net class, but was trying to keep this simple with the newer Powershell 3 commands.
Does anyone have any guidance or experience making this work?
The accepted answer won't do a multipart/form-data request, but rather a application/x-www-form-urlencoded request forcing the Content-Type header to a value that the body does not contain.
One way to send a multipart/form-data formatted request with PowerShell is:
$ErrorActionPreference = 'Stop'
$fieldName = 'file'
$filePath = 'C:\Temp\test.pdf'
$url = 'http://posttestserver.com/post.php'
Try {
Add-Type -AssemblyName 'System.Net.Http'
$client = New-Object System.Net.Http.HttpClient
$content = New-Object System.Net.Http.MultipartFormDataContent
$fileStream = [System.IO.File]::OpenRead($filePath)
$fileName = [System.IO.Path]::GetFileName($filePath)
$fileContent = New-Object System.Net.Http.StreamContent($fileStream)
$content.Add($fileContent, $fieldName, $fileName)
$result = $client.PostAsync($url, $content).Result
$result.EnsureSuccessStatusCode()
}
Catch {
Write-Error $_
exit 1
}
Finally {
if ($client -ne $null) { $client.Dispose() }
if ($content -ne $null) { $content.Dispose() }
if ($fileStream -ne $null) { $fileStream.Dispose() }
if ($fileContent -ne $null) { $fileContent.Dispose() }
}
The problem here was what the API required some additional parameters. Initial request required some parameters to accept raw content and specify filename/size. After setting that and getting back proper link to submit, I was able to use:
Invoke-RestMethod -Uri $uri -Method Post -InFile $filePath -ContentType "multipart/form-data"
I found this post and changed it a bit
$fileName = "..."
$uri = "..."
$currentPath = Convert-Path .
$filePath="$currentPath\$fileName"
$fileBin = [System.IO.File]::ReadAlltext($filePath)
$boundary = [System.Guid]::NewGuid().ToString()
$LF = "`r`n"
$bodyLines = (
"--$boundary",
"Content-Disposition: form-data; name=`"file`"; filename=`"$fileName`"",
"Content-Type: application/octet-stream$LF",
$fileBin,
"--$boundary--$LF"
) -join $LF
Invoke-RestMethod -Uri $uri -Method Post -ContentType "multipart/form-data; boundary=`"$boundary`"" -Body $bodyLines
For anyone wondering (like Jelphy) whether David's answer can be used with cookies/credentials, the answer is yes.
First set the session with Invoke-WebRequest:
Invoke-WebRequest -Uri "$LoginUri" -Method Get -SessionVariable 'Session'
Then POST to the Login URL, which stores the authentication cookie in $Session:
$Response = Invoke-WebRequest -Uri "$Uri" -Method Post -Body $Body -WebSession $Session
The steps above are the standard way to deal with session in Powershell. But here is the important part. Before creating the HttpClient, create an HttpClientHandler and set it's CookieContainer property with the cookies from the session:
$ClientMessageHandler = New-Object System.Net.Http.HttpClientHandler
$ClientMessageHandler.CookieContainer = $Session.Cookies
Then pass this object to the HttpClient constructor
$Client = [System.Net.Http.HttpClient]::new($ClientMessageHandler)
Voila, you now have an HttpClient with session cookies set automatically via Invoke-WebRequest. The rest of David's example should work (copied here for completeness):
$MultipartFormData = New-Object System.Net.Http.MultipartFormDataContent
$FileStream = [System.IO.File]::OpenRead($FilePath)
$FileName = [System.IO.Path]::GetFileName($FilePath)
$FileContent = New-Object System.Net.Http.StreamContent($FileStream)
$MultipartFormData.Add($FileContent, $FieldName, $FileName)
$Result = $Client.PostAsync($url, $content).Result
$Result.EnsureSuccessStatusCode()
I had many files to upload with each request, so I factored out this last bit into a lambda function:
function Add-FormFile {
param ([string]$Path, [string]$Name)
if ($Path -ne "")
{
$FileStream = [System.IO.File]::OpenRead($Path)
$FileName = [System.IO.Path]::GetFileName($Path)
$FileContent = [System.Net.Http.StreamContent]::new($FileStream)
$MultipartFormData.Add($FileContent, $Name, $FileName)
}
}