UnauthorizedAccessException from PowerShell when using Invoke-WebRequest - windows

I know that the error is pretty much self-explenatory but yet I am not able to find solution. I write a PowerShell script to automate the set-up project for the dev machines. There are a set of programs that must be installed so what I want to do i first download the file and then install it. I am having problems with downloading file from the web to the local machine.
My logic is as follows. I have an .xml file where I configure all the stuff. For the downloads it looks like this:
<download source="https://github.com/msysgit/msysgit/releases/download/Git-1.9.5-preview20150319/Git-1.9.5-preview20150319.exe"
destination="C:\Temp" filename="Git-1.9.5-preview20150319.exe"/>
Then in my PowerShell script file I have this function:
function install-tools() {
Set-ExecutionPolicy RemoteSigned
$xmlFileInformation = $config.SelectNodes("/setup/downloads/download");
Foreach ($file in $xmlFileInformation)
{
$("Filename: " + $file.filename)
$("File source: " + $file.source)
$("File destionation: " + $file.destination)
$("****************************************************************");
$("*** Downlading "+ $file.filename);
$("****************************************************************");
Invoke-WebRequest $file.source -OutFile $file.destination
}
$("Task finished");
}
After executin I get the error from the title UnauthorizedAccessException from PowerShell when using Invoke-WebRequest. Two things that I can mention is that I have included Set-ExecutionPolicy RemoteSigned and also, I execute the script running PowerShell as administrator. I've tried different paths but it's the same everytime, I don't get permission to write anywhere. The only thing that I can't try is using another drive I have only one - C:\.
And one strange thing - my destination directory is C:\Temp but during one of my attempts I didn't have such a directory in C:\ so I ended up with file named Temp in my C:\ but this was the closest I get to getting a file.
I don't need to save those files in a particular place since it's very possible to delete the entire directory after successfull set-up so what I need is a way to let powershell save files somewhere in my C:\ drive. Since I'm not sure if this is related with administrating my system and setting the correct rights (I tried to lower the protection as much as I can) or I miss something in my PowerShell script?

You does not specify file name to download to. Replace
-OutFile $file.destination
to
-OutFile (Join-Path $file.destination $file.filename)

Related

How to use Powershell to run a exe with a wildcard as the directory keeps changing with each install

I am attempting to run a .exe file for an app which is installed but requires to be activated. This would be a fairly easy process but the directory with .exe changes name slightly with each install. For example a number is added to each folder after the install (Different devices have different numbers) e.g. test1 and then test2. How could I use a wild card to target the folder as it changes?
Example code:
Start-Process -FilePath "\C:\ProgramData\app*/test.exe"
Please note: the app is not real, this is just for display purposes.
Your path seems to be incorrect. Wildcards should work in PowerShell. For example, the below wildcard works for me in PowerShell 5.0:
Try running Start-Process -FilePath "C:\ProgramData\app*\test.exe"

Batch file - pull commands from web resource

I've tried several solutions to no avail, but am looking for a solution as to create a batch file that will run any commands located in a remote .txt file located on a website.
For example, somebody clicks on a .bat and the .bat retrieves a list of commands from www.example.com/command.txt, and then runs the contents of the .txt as if the commands were specified explicitly in the original .bat file. I am not opposed to using PowerShell or VBScript.
In PowerShell you can do this: iex ((New-Object System.Net.WebClient).DownloadString('https://chocolatey.org/install.ps1'))
i.e. this downloads and runs the PowerShell script: https://chocolatey.org/install.ps1
Explanation
New-Object System.Net.WebClient creates a new instance of the .Net web client.
DownloadString('https://chocolatey.org/install.ps1') invokes the web client's Download method to pull back the text from this script (see https://msdn.microsoft.com/en-us/library/fhd1f0sw(v=vs.110).aspx).
iex is an alias for invoke-expression. This runs the downloaded string as if it were a command; i.e. causes PowerShell to execute the remote script.
Simpler Version
While the Chocolatey install script's an impressive 1 liner, the expanded version below may be simpler to understand (though ultimately does exactly the same as the above; just split over several lines).
$scriptUri = 'https://chocolatey.org/install.ps1'
$webClient = New-Object -TypeName 'System.Net.WebClient'
$scriptAsString = $webClient.DownloadString($scriptUri)
Invoke-Expression -Command $scriptAsString
The above example's taken from https://chocolatey.org/install

%~dp0 equivalent in powershell (using Expand-Archive cmdlet)

I'm pretty new to scripting (especially powershell) and new to Stack Overflow, so please, excuse my ignorance and please bear with me! I will do my best to specifically explain what I'm looking to do and hopefully someone can give a detailed response of what I could do to make it work..
Intended Process/Work Flow: A co-worker downloads "Install.zip" file that has all the necessary files. This "Install.zip" file contains "Setup.bat" file (for computer config), "Fubar.zip" file, 2 powershell scripts, and a custom powerplan (.pow) file. Once downloaded they will run the "Setup.bat" file and it will pretty much do all the work. Inside that batch file it calls 2 powershell scripts. 1)"Download.ps1" - Downloads some other files from the web. 2.) "Unzip.ps1" - Unzips "Fubar.zip" and places contents in another folder - C:\TEST\
Issue: I've recently gotten familiar with using %~dp0 in batch files. I want to make sure that the location where my co-worker initially downloads the Install.zip doesn't throw off my batch file. So for example.. some people will download .zip files to the "Downloads" folder, then extract contents to proper destination. Others will download the .zip to a specific folder, then extract it within that folder. [Ex: C:\Alex\Install.zip --Extraction-- C:\Alex\Install\((Content))] So I tried to not pre-define file locations due to the variables. I've gotten the %~dp0 to work everywhere I need it to in my batch file. The only issue I have is getting my powershell scripts to use same working directory that my batch file is in. *My batch file and my powershell scripts will always be in the same directory. (Wherever that may be)
Goal: I want my powershell script ("Unzip.ps1") to look for my "Fubar.zip" file in the same directory that its currently running in. (Again - Wherever that may be) I basically want to remove any variables that may throw off the powershell script. I want it to always use it's current working directory to locate Fubar.zip. I basically need powershell to either use its current working directory OR figure out a way to have it pull its current working directory and use that to look for "Fubar.zip".
my current "Unzip.ps1" powershell script is extremely basic.
Unzip.ps1:Expand-Archive -Force c:\ALEX\Install.zip\Fubar.zip -dest c:\TEST\
Batch File Command that calls the Unzip.ps1 script: Powershell.exe -executionpolicy remotesigned -File %~dp0UNZIP.ps1
Please keep in mind, I'm just learning scripting and I'm teaching myself. My knowledge is limited, but I've made it this far and this is the only part I'm stuck on. Please give clear responses. Any help or advice would be extremely appreciated! Using PowerShell 5.0
Thanks in advance!
The equivalent of cmd.exe's %dp0 in PowerShell v3+ is $PSScriptRoot:
Both constructs expand to the absolute path of the folder containing the batch file / PowerShell script at hand.
(The only difference is that %dp0 contains a trailing \, unlike $PSScriptRoot).
Thus, to make your Unzip.ps1 script reference Fubar.zip in the same folder that the script itself is located in, use:
Expand-Archive -Force $PSScriptRoot\Fubar.zip -dest c:\TEST\
Constructing the path as $PSScriptRoot\Fubar.zip - i.e., blindly joining the variable value and the filename with \ - is a pragmatic shortcut for what is more properly expressed as (Join-Path $PSScriptRoot Fubar.zip). It is safe to use in this case, but see the comments for a discussion about when Join-Path should be used.
The automatic $PSScriptRoot variable requires PS v3+; in v2-, use
Expand-Archive -Force ((Split-Path $MyInvocation.Mycommand.Path) + '\Fubar.zip') -dest c:\TEST\
From your description, I gather that Fubar.zip and Unzip.ps1 are in the same directory. We'll pretend this directory is C:\Users\Me\Temp; although I understand that may vary.
Powershell's working directory will be the directory you're in (if called from CMD) when you launch; otherwise, it'll be from $env:UserProfile. Since the .bat file always call Unzip.ps1 from the directory that it's in (C:\Users\Me\Temp), powershell.exe will find it with this command (you can still use %~dp0 here; it's not hurting anything):
powershell.exe -ExecutionPolicy RemoteSigned -File Unzip.ps1
Inside of Unzip.ps1, you'll use Get-Location:
Expand-Archive -Force "$(Get-Location)\Fubar.zip" -dest c:\TEST\
However, if the .bat file does a cd into another directory, this won't work. From your %~dp0UNZIP.ps1 example, I assume this isn't the case, but let's address it anyway. If this is the case, you need to process from where the location of the script is. So for this call the full/relational path to the .ps1:
powershell.exe -ExecutionPolicy RemoteSigned -File C:\Users\Me\Temp\Unzip.ps1
Then, your Unzip.ps1 will need to look like this:
Expand-Archive -Force "${PSScriptRoot}\Fubar.zip" -dest 'C:\TEST\'
Alternatively, you can also do some fancy path splitting, as #JosefZ suggested. The $PSCommandPath and $MyInvocation variables contain the full path to your script; which you should familiarize yourself with:
$location = Split-Path $PSCommandPath -Parent
$location = Split-Path $MyInvocation.MyCommand.Path -Parent
Expand-Archive -Force "${location}\Fubar.zip" -dest 'C:\TEST\'
Note: Of course, you wouldn't set $location twice. I'm just showing you two ways to set it.
I hope this helps!
Prior to Powershell 3
$currentScriptPath = Split-Path ((Get-Variable MyInvocation -Scope 0).Value).MyCommand.Path
Otherwise, $PsScriptRoot will work. If you're going to depend on it, though, I'd make sure you mark the script with #Requires -version 3
I'd advise against changing the PWD unless you must. Which is to say, reference the variable directly.

Invoke Windows copy from PowerShell

I am busy with creating a PowerShell script where a folder needs to be copied to another folder as a part of the script.
For this I would like to use the standard Windows copy interface and leverage from the prompts and selections like “There is already a file with the same name in this location.”, “Do you want to merge this folder”, “Do this for all”, etc. instead of programming this all myself.
I investigated a view directions:
Using the IFileOperation::CopyItem method as e.g. HowTo: Display progress dialog using IFileOperation but I could find any hint of how to embed this in PowerShell
Using Verbs() Copy/Paste but although the example Invoke-FileSystemVerb -Path "C:\TestDir -Verb Cut; Invoke-FileSystemVerb -Path "\\server\share" -Verb Paste” suggests otherwise, I can paste files that are manually copied/cut but could not copy/cut files with using the CmdLet or simply using the Verb.DoIt() method (I suspect this for a security reason).
Simulate a drag-drop?
But could not find any working solution.
Any suggestion how to do this from PowerShell?
I use this to extract from ZIP files which seems to come up with all the prompts and progress bar:
$shell = New-Object -Com Shell.Application
$folder = $shell.NameSpace(“$path\Folder”)
$shell.NameSpace($otherpath).CopyHere($folder)

PowerShell UnauthorizedAccessException writing file on network share

I'm trying to write a PowerShell script which minifies a directory full of .js files on the webserver. The files belong to me; I created it; I'm logged in as me. I can open and save the files in a text editor or via a batch file. The PowerShell script thinks it's operating as me ($env:username), and I'm running it from a PowerShell console that I ran with "Run As Administrator".
The loop looks like this. $files is confirmed to be a collection of file objects representing the files I want.
$tool = "c:\Program Files (x86)\Microsoft\Microsoft Ajax Minifier\ajaxmin.exe";
foreach($ofile in $files) {
$outfile = $ofile.DirectoryName + "\" + $ofile.BaseName + ".min.js";
& $tool $ofile.FullName > $outfile;
}
I get the following error on each file:
Access to the path '\\webserver\inetpub\whatever\js\validation.min.js' is denied.
At C:\minifyall.ps1:18 char:27
+ & $tool $ofile.FullName > <<<< $outfile;
+ CategoryInfo : OpenError: (:) [], UnauthorizedAccessException
+ FullyQualifiedErrorId : FileOpenFailure
The file there is the file it ought to be writing to, and get-acl tells me I have Allow FullControl. It can read the non-.min files just fine.
If I change the output directory to the current working directory (on my own machine), the script works as expected:
# No prob
$outfile = $ofile.BaseName + ".min.js";
Is there something else I need to do to enable this script to write to remote files? Other than rewriting it in Perl (Update: In the end, I rewrote it in Perl and as of February 2020 have had no trouble with it. This is not an endorsement of Perl).
Tips on PowerShell coding style are welcome too. My professional experience with PowerShell began approximately an hour after breakfast today.
Try and print all the full paths in order to see there isn't anything funny going on.
Another a reason could be that, since the target files are Javascript, some security system prevents access. Are you running an antivirus?
If all else fails, use Procmon to see what exactly is going on on the filesystem.
Keep in mind that file ACLs on the remote machine that grant you permission isn't enough. You also need permission to write on the share. Go to the remote machine, right click the folder, go to the Sharing tab, Advanced Sharing and click the Permissions button. Check those permissions to make sure you have write privileges.

Resources