Powershell file download issue - powershell

I'm trying to download the PuTTY executable using PowerShell, but could not get the file on temp path.
My script:
$Url = "https://the.earth.li/~sgtatham/putty/latest/x86/putty.exe"
$Path = "C:%homepath%\AppData\Local\Temp\putty.exe"
$Wc = New-Object System.Net.WebClient
$Wc.DownloadFileAsync($Url,$Path)
I am executing following command via CMD:
powershell.exe "-ExecutionPolicy" "RemoteSigned" "-file" "test.ps1"

You have two problems, both of which need to be corrected for your script to have a chance of working.
The command for executing a Powershell script from within CMD.EXE should not have the arguments quoted:
powershell.exe -ExecutionPolicy RemoteSigned -file test.ps1
To expand a system environment variable from within powershell, you do not surround it with % as you do in CMD. See http://ss64.com/ps/syntax-env.html for more information; assuming that the environment variable HOMEPATH exists, you would reference it in Powershell as $env:homepath, not %homepath%.

The %VAR% form is not used in powershell, this is only used in CMD. In PowerShell you need to use $env:VAR instead.
You can run Get-ChildItem Env: to get a list of all the Environmental Variables you can use.
For your script try this:
$Path = "$env:USERPROFILE\AppData\Local\Temp\putty.exe"
I've used USERPROFILE instead of HOMEPATH as this includes the drive letter so your script will still work if a different letter is used.

Related

How to run powershell script from .ps1 file?

I'm trying to automate the execution of a simple PS script (to delete a certain .txt file). Obviously, I'm new to powershell :)
When I run the code in shell, it works flawless. But when i save the code as a .ps1 and double-click it (or execute it remotely), it just pops up a window and does nothing.
I've tried to save the code as a .bat file and execute it on Windows command line, but it behaves the same: Works by coding directly on prompt, but doesn't Works by executing the .bat file.
$Excel = New-Object -ComObject Excel.Application
$Workbook = $Excel.Workbooks.Open('H:\codes\test1.xlsm')
$workSheet = $Workbook.Sheets.Item(2)
$str_name = $WorkSheet.Cells.Item(2,1).Text
Remove-Item -Path "H:\text files\$str_name.txt" -Force
I expected it to work by double-clicking it, just as it does by running in shell, or in the command line, but i can't figure out why it doesn't.
Create a batch file which points at your .ps1 file. You may be required to run the batch file with elevated permissions, depending on your access levels (the logged in account will be used for execution).
E.g.:
Powershell.exe -executionpolicy remotesigned -File "C:\Path\script.ps1"
If this still isn't working, please execute your batch file via CMD (copying the path, wrapped in quotation marks, into CMD) and let me know the response.
There are several ways to run a .ps1 file. The simplest way is to right-click the file and choose 'Run with PowerShell'.
As others have suggested, you can also run your .ps1 file using powershell.exe either in command prompt or from a BATCH or CMD file. As follows:
powershell.exe -File C:\Script.ps1
If you are still having problems it could be the execution policy. For this, simply add -ExecutionPolicy Bypass to your command as follows:
powershell.exe -File C:\Script.ps1 -ExecutionPolicy Bypass
To change your execution policy you can use:
Set-ExecutionPolicy

Is it possible to get the caller's directory in PowerShell script when calling from CMD or batch file?

Let's say I type this in CMD from C:\source:
powershell.exe Set-ExecutionPolicy RemoteSigned -File C:\test\test.ps1
In test.ps1 I try to get C:\source as directory without success.
$script_folder = $PSScriptRoot
$myDir = Split-Path -Parent $MyInvocation.MyCommand.Path
$myDir
$PSScriptRoot
Both $myDir and $PSScriptRoot returns C:\test\ instead of C:\source.
You could use $PWD which is the Automatic variable for Present Working Directory. When you open PowerShell it should continue to use the same working directory.
From about_automatic_variables
$PWD
Contains a path object that represents the full path of the current directory.
Also MS-DOS is an Operating System which cannot run PowerShell. This is different from cmd.exe aka Command Prompt in Windows.
The automatic variables you are using are information about the script invocation. The location from which the command to launch the script was initiated is part of the environment.
$PWD contains information about the present working directory (nod to posix pwd command). Specifically, $PWD.Path.
Per the about_automatic_variables page (or Get-Help about_automatic_variables), $PSScriptRoot, $PSCommandPath, are properties of $MyInvocation.
See here for an example of using Split-Path -Path $($Global:$MyInvocation.MyCommand.Path) to get the current path.
Recommend a test script:
# TestInvocationAndPWDPaths.ps1
function Test-MyInvocation {
$MyInvocation
}
function Test-PWD {
$PWD
}
'$MyInvocation from script:'
$MyInvocation
'$MyInvocation from function:'
Test-MyInvocation
'$PWD from script:'
$PWD
'$PWD from function'
Test-PWD
Has interesting results. Running this from powershell console, and from ISE, and from command prompt will show you the differences in $MyInvocation.
$MyInvocation.PSScriptRoot gives you the caller scripts folder.
When the caller is command line, this will return $null.
You should be able to use these two facts.
Just want to add that it is a general pitfall in powershell to use $pwd/get-location inside psm1 functions.
Instead inject the full paths as parameters.

parse error in one-line powershell script

I am trying to create a one-line powershell script that just requests an url. The script is working fine when I run it as a ps1 file:
File "test.ps1":
$webclient=New-Object "System.Net.WebClient"
$data=$webclient.DownloadString("https://google.com")
I run this script in PS console like this:
PS C:\test.ps1 -ExecutionPolicy unrestricted
This runs without any problem, but when I try to schedule this script and make it a one-line according to these recommendations i.e. replace "" with '' and separate commands with ; so the result will be:
one-line:
powershell -ExecutionPolicy unrestricted -Command "$webclient=New-Object 'System.Net.WebClient'; $data=$webclient.DownloadString('https://google.com');"
Then I got the following problem:
Error:
The term '=New-Object' is not recognized as the name of a cmdlet,
function, script file, or operable program
I tried another script that also works fine as ps1 file, but not working as one-liner:
$request = [System.Net.WebRequest]::Create("https://google.com")
$request.Method = "GET"
[System.Net.WebResponse]$response = $request.GetResponse()
echo $response
one-line:
powershell -ExecutionPolicy unrestricted -Command "$request = [System.Net.WebRequest]::Create('https://google.com'); $request.Method = 'GET'; [System.Net.WebResponse]$response = $request.GetResponse(); echo $response"
Error:
Invalid assignment expression. The left hand side of an assignment
operator needs to be something that can be assigned to like a variable
or a property. At line:1 char:102
According to get-host command I have powershell v 2.0. What is the problem with one-line scripts above?
Put the statements you want to run in a scriptblock and run that scriptblock via the call operator:
powershell.exe -Command "&{$webclient = ...}"
Note that pasting this commandline into a PowerShell console will produce a misleading error, because PowerShell (the one into which you paste the commandline) expands the (undefined) variables in the string to null values, which are then auto-converted to empty strings. If you want to test a commandline like this, run it from CMD, not PowerShell.
It might also be a good idea to have the scriptblock exit with a status code, e.g.
&{...; exit [int](-not $?)}
or
&{...; $status=$response.StatusCode.value__; if ($status -eq 200) {exit 0} else {exit $status}}

put a powershell script on path through powershell commands.

I have a powershell script that I want to run from cmd/ps any location by putting it in path.
What is the command that can achieve that ?
I m basically looking for a UNIX equivalent of putting your script in bashrc and thus available from anywhere to run.
echo 'export PATH=$PATH:/path/to/script' >> ~/.bashrc && source ~/.bashrc
In windows you also have the system variable PATH that's used for defining where to locate executables.
You could do the following that should be equivalent assuming you're only using Powershell:
$newPath = "c:\tmp\MyScriptPath";
[Environment]::SetEnvironmentVariable('PATH', "$($env:Path);$newPath", [EnvironmentVariableTarget]::User);
# Update the path variable in your current session; next time it's loaded directly
$env:Path = "$($env:Path);$newPath";
You can then execute your script directly in Powershell with just the name of the script.
However_ : this will not work under cmd because cmd doesn't know how to handle the ps1 script as an executable. Normally one would execute the script from cmd by calling the following:
Powershell.exe -executionpolicy remotesigned -File C:\Tmp\Script.ps1
If this is "unacceptable" for you, the easiest way is to create a bat script along with your ps1 script (same path) and add the following content :
Script.bat (Assuming you have Script.ps1 in the same folder):
#ECHO OFF
PowerShell.exe -Command "& '%~dpn0.ps1'"
PAUSE
This will create the wrapper needed to Invoke Script anywhere in your cmd as batch files can be executed from cmd

PowerShell: Run command from script's directory

I have a PowerShell script that does some stuff using the script’s current directory. So when inside that directory, running .\script.ps1 works correctly.
Now I want to call that script from a different directory without changing the referencing directory of the script. So I want to call ..\..\dir\script.ps1 and still want that script to behave as it was called from inside its directory.
How do I do that, or how do I modify a script so it can run from any directory?
Do you mean you want the script's own path so you can reference a file next to the script? Try this:
$scriptpath = $MyInvocation.MyCommand.Path
$dir = Split-Path $scriptpath
Write-host "My directory is $dir"
You can get a lot of info from $MyInvocation and its properties.
If you want to reference a file in the current working directory, you can use Resolve-Path or Get-ChildItem:
$filepath = Resolve-Path "somefile.txt"
EDIT (based on comment from OP):
# temporarily change to the correct folder
Push-Location $dir
# do stuff, call ant, etc
# now back to previous directory
Pop-Location
There's probably other ways of achieving something similar using Invoke-Command as well.
There are answers with big number of votes, but when I read your question, I thought you wanted to know the directory where the script is, not that where the script is running. You can get the information with powershell's auto variables
$PSScriptRoot # the directory where the script exists, not the
# target directory the script is running in
$PSCommandPath # the full path of the script
For example, I have a $profile script that finds a Visual Studio solution file and starts it. I wanted to store the full path, once a solution file is started. But I wanted to save the file where the original script exists. So I used $PsScriptRoot.
If you're calling native apps, you need to worry about [Environment]::CurrentDirectory not about PowerShell's $PWD current directory. For various reasons, PowerShell does not set the process' current working directory when you Set-Location or Push-Location, so you need to make sure you do so if you're running applications (or cmdlets) that expect it to be set.
In a script, you can do this:
$CWD = [Environment]::CurrentDirectory
Push-Location $MyInvocation.MyCommand.Path
[Environment]::CurrentDirectory = $PWD
## Your script code calling a native executable
Pop-Location
# Consider whether you really want to set it back:
# What if another runspace has set it in-between calls?
[Environment]::CurrentDirectory = $CWD
There's no foolproof alternative to this. Many of us put a line in our prompt function to set [Environment]::CurrentDirectory ... but that doesn't help you when you're changing the location within a script.
Two notes about the reason why this is not set by PowerShell automatically:
PowerShell can be multi-threaded. You can have multiple Runspaces (see RunspacePool, and the PSThreadJob module) running simultaneously withinin a single process. Each runspace has it's own $PWD present working directory, but there's only one process, and only one Environment.
Even when you're single-threaded, $PWD isn't always a legal CurrentDirectory (you might CD into the registry provider for instance).
If you want to put it into your prompt (which would only run in the main runspace, single-threaded), you need to use:
[Environment]::CurrentDirectory = Get-Location -PSProvider FileSystem
This would work fine.
Push-Location $PSScriptRoot
Write-Host CurrentDirectory $CurDir
I often used the following code to import a module which sit under the same directory as the running script. It will first get the directory from which powershell is running
$currentPath=Split-Path ((Get-Variable
MyInvocation -Scope
0).Value).MyCommand.Path
import-module "$currentPath\sqlps.ps1"
I made a one-liner out of #JohnL's solution:
$MyInvocation.MyCommand.Path | Split-Path | Push-Location
Well I was looking for solution for this for a while, without any scripts just from CLI. This is how I do it xD:
Navigate to folder from which you want to run script (important thing is that you have tab completions)
..\..\dir
Now surround location with double quotes, and inside them add cd, so we could invoke another instance of powershell.
"cd ..\..\dir"
Add another command to run script separated by ;, with is a command separator in powershell
"cd ..\..\dir\; script.ps1"
Finally Run it with another instance of powershell
start powershell "cd..\..\dir\; script.ps1"
This will open new powershell window, go to ..\..\dir, run script.ps1 and close window.
Note that ";" just separates commands, like you typed them one by one, if first fails second will run and next after, and next after... If you wanna keep new powershell window open you add -noexit in passed command . Note that I first navigate to desired folder so I could use tab completions (you couldn't in double quotes).
start powershell "-noexit cd..\..\dir\; script.ps1"
Use double quotes "" so you could pass directories with spaces in names e.g.,
start powershell "-noexit cd '..\..\my dir'; script.ps1"