I am fairly new to powershell and I am trying to create a script that executes a .exe file. I can execute them on my machine no problem because the folder path is hard coded. The problem is that if I shift this script to another computer, the .exe it calls might be located in a different folder structure. Example
My computer:
D:\Folder1\subfolder\RunMe.exe
Client computer might be
D:\RunMe\subfolder\RunMe.exe
I just need it to execute the RunMe.exe no matter where it is. Is there a way to do this in powershell?
# 1. Get the location of RunMe.exe
$RunMe = Get-ChildItem -Path d:\* -Include RunMe.exe -Recurse;
# 2. Invoke RunMe.exe
Start-Process -FilePath $RunMe[0].FullName -Wait -NoNewWindow;
Related
I have a Powershell script to create a self-extracting archive via 7zip. But it's receiving this error:
cannot find specified SFX module
The Powershell code is:
set-alias sz "$env:ProgramFiles\7-Zip\7z.exe
sz a -t7z -sfx -ppassword $fullpath $filetostore
Both variables are valid. I've tried -sfx and -sfx7z.sfx, same error. The 7z.sfx file is indeed in the correct folder with 7zip. I can also verify the alias is working, as the 7zip copyright appears when running the code (so 7zip commandline is being initiated). This command works outside Powershell.
I'm also tried Set-Location into the 7zip folder, but same error. What am I missing?
It seems you should add the 7-zip folder to your PATH environment variable to make things easier :
#find the 7-zip folder path
$7zPath = (Get-ChildItem "C:\Program Files","C:\Program Files (x86)" -Include "7-zip" -Recurse -ErrorAction SilentlyContinue).FullName
#add it to PATH environment variable
$env:Path += ";$7zPath;"
Then you can run 7z -sfx with no errors about the SFX module.
While Sodawillow has an answer that will work for the active session, a more permanent answer would be to add 7zip to the path for the Environment you are working in:
[Environment]::SetEnvironmentVariable("Path",$env:Path+";C:\Program Files\7-zip", [EnvironmentVariableTarget]::User)
The above one-liner should add 7zip to the active user account's path. Change 'User' to 'Machine' for the whole computer, or 'Process' for the currently running window. If you set 'User' or 'Machine', you will need to open a new powershell instance to see the change reflected.
I'm tasked with writing a powershell script to perform a file download, which will eventually be executed as a scheduled task once a week. I have no background in programming in the windows environment so this has been an interesting day.
I am experiencing a problem with the unexpected handling of the $pwd and $home of the shell.
I pass into my program a download URL and a destination file. I would like the destination file to be a relative path, e.g., download/temp.txt.gz
param($srcUrl, $destFile)
$client = new-object System.Net.WebClient
$client.DownloadFile($srcUrl, $destFile)
Ungzip-File $destFile
Remove-Item $destFile
This actually fails on the call to Remove-Item. If $destFile is a relative path then the script happily downloads the file and puts it in a file relative to $home. Likewise, I then unzip this and my function Ungzip-File makes use of System.IO.Filestream, and it seems to find this file. Then Remove-Item complains that there is no file in the path relative to $pwd.
I am a bit baffled, as these are all part of the shell, so to speak. I'm not clear why these functions would handle the path differently and, more to the point, I'm not sure how to fix this so both relative and absolute paths work. I've tried looking at the io.path methods but since my $home and $pwd are on different drives, I can't even use the IsPathRooted which was seemed so close when I found it.
Any help?
You have to be aware of where you are in the path. $pwd works just fine on the command shell but let's say you have started your script from a scheduled job. You might think $pwd is where your script resides and code accordingly but find out that it actually uses, say %windir%\system32.
In general, I would use fullpath to destination and for paths relative to script folder I would use $PSScriptRoot/folder_name/file_path.
There are catches there too. For example, I noticed $PSScriptRoot will resolve just fine within the script but not within Param() block. I would highly suggest using write-verbose when coding and testing, so you know what it thinks the path is.
[CMDLETBINDING()] ## you need this!
Param()
write-verbose "path is $pwd"
Write-Verbose "removing $destFile"
Remove-Item $destfile
and add -verbose when you are calling your script/function:
myscript.ps1 -verbose
mydownloadfunction -verbose
To use a relative path, you need to specify the current directory with ./
Example: ./download/temp.txt.gz
You can also change your location in the middle of the script with Set-Location (alias: cd)
I was going to write up a simple alias 'iis' to invoke the IIS Manager, which is 'C:\Windows\System32\inetsrv\InetMgr.exe'
set-alias iis "OpenIIS.ps1"
and in the OpenIIS.ps1 I have
$item = "C:\Windows\system32\inetsrv\InetMgr.exe"
invoke-item -path $item
This doesn't work. The error I get is "The system cannot find the file specified"
In fact, just doing a Get-ChildItem on the inetsrv won't show the InetMgr.exe (no difference with -Force switch)
Get-ChildItem C:\Windows\system32\inetsrv\*.exe -force
Obviously I can see it in Explorer and I can launch it using cmd, but not with Powershell it seems. Also, Powershell is running as Administrator.
What is going on?
As a workaround I tried creating a link to the file and then invoking that link from Powershell. I now get a 'NotSpecified' Win32Exception.
I have originally used 64 bit Powershell, but get the same result on the x86 Powershell (both run as Administrator)
Are you at the elevated PowerShell prompt? Some system files may not show up unless you use -Force parameter with Get-ChildItem.
I think evidently the file InetMgr.exe is not there as when I do a get-childitem in the mentioned directory,it lists the "InetMgr.exe" there.
This may not be the problem with Get-ChildItem or the Alias you created but instead with ur IIS Server.
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"
I am on a Windows 7 machine trying to execute a PowerShell script to copy a template directory to another directory. The command I am executing looks like:
Copy-Item -path "$projectsFolder$SourceFolder" -destination "$Test" -recurse -verbose;
The parameters are as follows:
path: C:\Users\username\Documents\Visual Studio 2010\Projects\TemplateSolution\Source
Destination: C:\Users\username\Documents\Visual Studio 2010\Projects\test\source\main
When I run this command at a PowerShell prompt, the files are copied correctly. If I try and execute the command in the script with verbose enabled, it appears to copy the files and directories, but only the top level directory is created in the file system. I am not sure why this would happen and I would appreciate any guidance or troubleshooting steps to perform.
Make sure you put quotes around the directory names if they have spaces in them. Also, you may need the -Force parameter to create destination directories if they do not exist.