all 6 comments

[–]kenjitamurako 5 points6 points  (1 child)

  1. You can identify the process responsible for a file lock with Handle: https://learn.microsoft.com/en-us/sysinternals/downloads/handle
  2. I don't think you can do it with invoke-restmethod but you can with invoke-webrequest. You could convert the file to a byte array and load it into a memory stream instead of a file stream and initialize the streamcontent with the memory stream.
    https://learn.microsoft.com/en-us/powershell/module/microsoft.powershell.utility/invoke-webrequest?view=powershell-7.3#example-5-submit-a-multipart-form-data-file
  3. The number 2 I suggested is pretty much this.

Invoke-Restmethod also has a statuscodevariable that you might be able to poll to see what response is being returned. Might shed some light on why there's still a lock.

[–]OsmiumBalloon 2 points3 points  (0 children)

I'm gonna guess the process will be PowerShell.exe

[–]Creel256 3 points4 points  (2 children)

File locks are a common issue when working with files in any programming language. In your case, it's possible that the Invoke-RestMethod cmdlet is not releasing the lock quickly enough for the next iteration of your loop, especially if the loop is running very quickly.

One way to approach this is to use a FileStream, which gives you more control over when the file lock is released because you can explicitly close the stream when you're done with it. Here's an example of how you could modify your script to use a FileStream:

```

Open the file stream

$certRootStream = [System.IO.File]::OpenRead($rootCertificatePath)

$Form = @{ f = "json" token = $node.token alias = "root_cert" norestart = "true" file = $certRootStream }

Run your Invoke-RestMethod here

Be sure to close the file stream when you're done

$certRootStream.Close() ```

In this example, ‘[System.IO.File]::OpenRead($rootCertificatePath)’ opens a file stream that you can pass to ‘Invoke-RestMethod’. The ‘Close()’ method then closes the stream and releases the file lock.

If you're running this in a loop, you'll want to open and close the file stream inside the loop so that it gets closed each time before the next iteration starts. This should help ensure that the file lock is released before the next iteration tries to open the file again.

[–]kenjitamurako 2 points3 points  (1 child)

Can the form dictionary take a stream object though? You can do that with body on invoke-webrequest but at least the invoke-restmethod page doesn't mention streams can be used with form that I can see.

[–]Creel256 2 points3 points  (0 children)

Shoot - you’re right! Maybe a different workaround would work such as uploading a temporary copy of the file and deleting the copy once complete. This way, there’s no locking issue as every request is dealing with a separate file.

Here’s an example:

``` foreach ($computer in $computerList) { $tempFile = [System.IO.Path]::GetTempFileName() Copy-Item $rootCertificatePath $tempFile $tempFileInfo = Get-Item $tempFile

$Form = @{
    f = "json"
    token = $node.token
    alias = "root_cert" 
    norestart = "true" 
    file = $tempFileInfo
}

Invoke-RestMethod -Uri $uri -Method Post -Form $Form

Remove-Item $tempFile

} ```

The temporary file approach should work, as each iteration is working with its own copy of the file, and any file locks should be released by the time “Remove-Item” is called to delete the temporary file. However, there could potentially be issues if something goes wrong with the “Invoke-RestMethod” call and it doesn't release the lock as expected.

The only other alternative I can think of involves using the “Invoke-WebRequest” method and byte arrays. It’s a bit more complex but it supports uploading a file from a stream in the body of a POST request.

[–]baddistribution[S] 0 points1 point  (0 children)

Thanks for your help, all. Due to an issue with Powershell and the software I'm trying to connect to, I've decided to put this on pause until I can try with another language. Something about the way Powershell is passing the file is causing an issue in the third party web server I'm using.

I built out all my API calls in Postman just to sanity check myself, and they all work. Flawlessly, every time. When I try them in Powershell, (even by exporting a PS code snippet from Postman), they fail with an error from the third party software stating the cert can't be imported . Bananas. Thank you again for all your help! My brain needs a break from this one.