Using Invoke-restmethod gives "access to the path <path> is denied - windows

I am trying to send a file via multipart formdata via invoke-restmethod. I don't have write permmision on the server but type filename works fine
My command is Invoke-RestMethod -Uri url -Method Post -infile file

Maybe file is not available in the PowerShell if its on a network location or if it is read only.
The read only problem is described here: https://www.reddit.com/r/PowerShell/comments/pwhsw2/invokerestmethod_method_put_infile_doesnt_work/
basically it is changing permissions as PowerShell has bug here:
Set-ItemProperty -Path <path> -Name IsReadOnly -Value $False
Then try again. If you can't change permissions you might switch to PowerShell 7

Related

How do I query Azure DevOps (TFS) using curl.exe or PowerShell directly without additional support libraries?

Azure DevOps has a REST API: https://learn.microsoft.com/en-us/rest/api/azure/devops/?view=azure-devops-rest-7.1
How do I access it using curl.exe or PowerShell without additional support libraries?
This instructions are for Windows, although they can be used in other platforms with slight modification.
Below, replace with your own values for:
{organization}
{project}
{team}
{pat}
You can create a PAT in your organization's portal. Using your browser, go to: (replace {organization}):
https://dev.azure.com/{organization}/_usersSettings/tokens
Using Command Prompt
If using Command Prompt (cmd.exe), curl.exe can be used. It is part of Windows (10+). Also works in PowerShell, but you have to spell out curl.exe, not just curl. The commands below output the results to the console. You can pipe it to a file, or use the -o option in curl to specify a file to output to.
Using PoowerShell
If using PowerShell, you use the Invoke-RestMethod command. In the below commands, the result of the command is placed in a variable, $result, which you can use after the invocation.
The commands below also assume variables $pat and $header are initialized as follows:
$pat = "{pat}"
$header = #{authorization = "Basic $([System.Convert]::ToBase64String([System.Text.Encoding]::ASCII.GetBytes(":$($pat)")))"}
Example getting a work item by ID (Work Items - Get Work Item):
Using curl:
curl.exe -u :{pat} -H "Content-Type: application/json" https://dev.azure.com/{organization}/_apis/wit/workItems/{id}
Using PowerShell:
$url = "https://dev.azure.com/{organization}/_apis/wit/workItems/{id}"
$entries = Invoke-RestMethod -Uri $url -Method Get -ContentType "application/json" -Headers $header
Quick display of the above output:
$entries.Fields | Format-Table system.workitemtype, system.title

Install winget by the command line (powershell)

I'm trying to write a PowerShell script to setup windows dev machines. I want to use winget but I don't see any easy way just to install winget using the commandline. You have to either use the windows store or download the msxibundle from github.
Invoke-WebRequest -Uri https://github.com/microsoft/winget-cli/releases/download/v1.3.2691/Microsoft.DesktopAppInstaller_8wekyb3d8bbwe.msixbundle -OutFile .\MicrosoftDesktopAppInstaller_8wekyb3d8bbwe.msixbundle
Both of these require user's interaction instead of just running the script and walking away. Is there a better way? Thanks.
I devised a somewhat different approach, which installs the latest version:
# get latest download url
$URL = "https://api.github.com/repos/microsoft/winget-cli/releases/latest"
$URL = (Invoke-WebRequest -Uri $URL).Content | ConvertFrom-Json |
Select-Object -ExpandProperty "assets" |
Where-Object "browser_download_url" -Match '.msixbundle' |
Select-Object -ExpandProperty "browser_download_url"
# download
Invoke-WebRequest -Uri $URL -OutFile "Setup.msix" -UseBasicParsing
# install
Add-AppxPackage -Path "Setup.msix"
# delete file
Remove-Item "Setup.msix"
Using Windows PowerShell, not PowerShell Core, there's a command to help: Add-AppXPackage:
Add-AppXPackage -Path .\MicrosoftDesktopAppInstaller_8wekyb3d8bbwe.msixbundle
Should allow you to install the package.
Hope this helps

Accessing SMB share from Windows when using Powershell

I'm trying to build a custom VeeamZip backup script using PowerShell from a Windows 7 box. The box doesn't have the space requirements to hold the actual data itself, it's just the catalyst to manage the VeeamZip files.
I've been hunting around and found a solution here on SO to work around the fact that the PS-Drive command doesn't function using the -Credentials flag in PowerShell 2.0 using this snippet:
$net = new-object -ComObject WScript.Network
$net.MapNetworkDrive("u:", "\\share\point", $false, "user", "pass")
I can verify this is properly mounting the share and is searchable using Powershell, but when using the VeeamZip Powershell commands, the path U:\ isn't available.
I tried then using the net use command in Powershell which also mounted the volume, but even with /persistent:yes it won't show in Explorer and the backups fail.
What can I do? There has to be option to get this to work. I'm a Linux guy so I'm not powershell wiz.
EDIT: I've now updated to Powershell 3.0 and I still can't get it work...
I'm trying the following snippet, but only Powershell has access the new drive:
$credential = Get-Credential
New-PSDrive -Name V -PSProvider FileSystem -Root \\server\share -Credential $credential -Persist
EDIT: The New-PSDrive function now works to mount the volume in Explorer and can be browsed as expected as long as I don't launch PowerShell as administrator. The dilemma is now that I can't use the VeeamZip tool because it requires Admin to function. Ideas welcome.

Running a remote PowerShell script with a Git command in it results in NativeCommandError

I am getting an error while executing a remote PowerShell script. From my local machine I am running a PowerShell script that uses Invoke-Command to cd into a directory on a remote Amazon Windows Server instance, and a subsequent Invoke-Command to execute script that lives on that server instance. The script on the server is trying to git clone a repository from GitHub. I can successfully do things in the server script like "ls" or even "git --version". However git clone, git pull, etc. result in the following error:
Cloning into 'MyRepo'... + CategoryInfo : NotSpecified: (Cloning into 'MyRepo'...:String) [], RemoteException + FullyQualifiedErrorId : NativeCommandError
This is my first time using PowerShell or a Windows Server. Can anyone provide some direction on this problem.
The client script:
$s = new-pssession -computername $server -credential $user
invoke-command -session $s -scriptblock { cd C:\Repos; ls }
invoke-command -session $s -scriptblock { param ($repo, $branch) & '.\clone.ps1' -repository $repo -branch $branch} -ArgumentList $repository, $branch
exit-pssession
The server script:
param([string]$repository = "repository", [string]$branch = "branch")
git --version
start-process -FilePath git -ArgumentList ("clone", "-b $branch https://github.com/MyGithub/$repository.git") -Wait
I've changed the server script to use start process and it is no longer throwing the exception. It creates the new repository directory and the .git directory but doesn't write any of the files from the github repository. This smells like a permissions issue. Once again invoking the script manually (remote desktop into the amazon box and execute it from powershell) works like a charm.
Anytime you're calling an external executable from PowerShell, I highly recommend using Start-Process. The Start-Process cmdlet handles command line arguments much better, as compared to calling the executables directly.
Important: You must also be aware that if you run two separate Invoke-Command commands (unless you're using the -Session parameter) that you will be operating in two completely distinct PowerShell Remoting sessions! If you use the cd (aka. which is an alias for Set-Location) command, the results of that command will not persist into the new session when you run your Git command.
$GitExe = '{0}\path\to\git.exe' -f $env:SystemDrive;
$ArgumentList = 'clone "c:\path\with spaces\in it"';
Start-Process -FilePath $GitExe -ArgumentList $ArgumentList -Wait -NoNewWindow;
There is also a -WorkingDirectory parameter on the Start-Process cmdlet, that allows you to specify the Working Directory for a process. Instead of using the Set-Location cmdlet to set the "current directory" of the PowerShell session, you're probably better off specifying the full path to the working directory for the process. For example, let's say you had a Git repository in c:\repos\repo01, and your Git exe was in c:\git. You shouldn't worry so much about where PowerShell's "current directory" is, and rather focus on specifying the full paths to:
The Git executable
The Git repositories
Here's an example of how to achieve that:
Start-Process -FilePath c:\git\git.exe -ArgumentList 'clone "c:\repos\repo01" "c:\repos\repo02"" -Wait -NoNewWindow;
Note: I don't know the Git commands, but you should be able to adjust the value of the $ArgumentList variable above, to make it work for you. In PowerShell, you can put double-quotes inside of single-quotes, without having to worry about escaping them.

PowerShell equivalent for cURL command uploading file

I am able to send HTTP POST a text file to my server using the following cURL command:
curl -i -F file=#file.txt http://www.website.com/put_file
The server is expecting a file from $_FILES['file'].
I have the following so far but it is not working:
$url = http://www.website.com/put_file
$file = "c:\file.txt"
$wc = new-object System.Net.WebClient
$wc.UploadFile($url, $file.FullName)
it returns 0, and it did not upload to the server
How can I send the file as $_FILES['file']? Also, how can I see the response from the server?
I think it should be something like this:
$body = "file=$(get-content file.txt -raw)"
Invoke-RestMethod -uri http://www.websetite.com/put_file -method POST -body $body
Note: this does require PowerShell V3. Also, you might need to specify the -ContentType parameter as "application/x-www-form-urlencoded". I recommend getting Fiddler2 and use it to inspect the request in both the curl and Inovke-RestMethod cases to help get the irm parameters correct. This is assuming the file contents are fairly small and non-binary. If not, you probably need to go to content type multipart/form-data.
In Powershell you can use curl.exe instead of curl (yes, are different commands: http://get-cmd.com/?p=5181)
curl.exe -i -F file=#file.txt http://www.website.com/put_file
Or you can use Invoke-RestMethod from powershell 3
More details about Invoke-RestMethod from powershell 3 at: https://superuser.com/questions/344927/powershell-equivalent-of-curl
To solve this, I download curl.exe for windows, and still used curl.
After a couple hours of using fiddler to try to match curl, I gave up and just used this guy's function (See link below). Worked like a charm.
http://blog.majcica.com/2016/01/13/powershell-tips-and-tricks-multipartform-data-requests/

Resources