PowerShell - Including .ps1 files - invoke from other folder - powershell

Im struggling with a PowerShell challenge, the setup is as follows:
In the C:\update folder I have ReInstall.ps1 powershell script, that will try to run a script in a folder on another drive:
q:\test\install.ps1
In the q:\test folder, I have a Powershell file callled Install.ps1 that tries to include another ps file called InstallFunctions.ps1
. .\installfunctions.ps1
The two Install ps files works nicely when executed from the q:\test\folder.
But if I try to run the ReInstall.ps1 script from the c:\Update folder, it nicely starts the q:\install.ps1, but then fails because it can't find the Installfunctions.ps1.
It tries to find the InstallFunctions.ps1 in the c:\update folder, instead of the q:\test folder.
The term '.\installfunctions.ps1' is not recognized as the name of a cmdlet, >function, script file, or operable program.
Check the spelling of the name, or if a path was included, verify that the path >is correct and try again.
Since the Install ps files are inside a ISO file, and must work in any scenario, I can't change them. So I have to figure out a way to make the Install.ps1 believe it runs from q:\test folder.

You have to retrieve the script folder like this (PS 2.0):
$scriptPath = Split-Path $MyInvocation.MyCommand.Definition
. "$scriptPath\installfunctions.ps1"
#or . (Join-Path $scriptPath "installfunctions.ps1")
In PS 3.0 $PSScriptRoot holds the info you need:
. "$PSScriptRoot\installfunctions.ps1"
#or . (Join-Path $PSScriptRoot "installfunctions.ps1")

Related

Run Executable (with Support Files) In a Separate Directory

I'm attempting to run "AutoRun.exe" from an iso file mounted to DriveLetter:\
& "${DriveLetter}:\AutoRun.exe"
Using the above method I can properly tell PowerShell to run the executable, but it expects the support files (AutoRun.cfg, etc) to be in the place of execution (in this case my Desktop). I want this to be able to work no matter the location of the PowerShell script.
Any suggestions?
Change the working directory to whereever the required files are located. If they reside in ${DriveLetter}:\ change to that directory:
Set-Location "${DriveLetter}:\"
& "${DriveLetter}:\AutoRun.exe"
If they reside in the same folder as the PowerShell script change to that directory:
Set-Location (Split-Path -Parent $MyInvocation.MyCommand.Definition)
& "${DriveLetter}:\AutoRun.exe"
or (PowerShell v3 and newer):
Set-Location $PSScriptRoot
& "${DriveLetter}:\AutoRun.exe"

How to properly set path in Powershell and 7zip?

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.

Import Carbon Powershell Module from shared folder

I use Powershell Remoting version 2.0.
I have downloaded the Carbon Powershell Module. I copied it in shared folder:
\SharedServer\PowershellModules\Carbon-1.0.0
In my script ps1, I have this source code:
$PSPathCarbon = "\\SharedServer\PowershellModules\Carbon-1.0.0\Carbon"
. (Join-Path $PSPathCarbon Import-Carbon.ps1)
I get the following error:
The term
'\SharedServer\PowershellModules\Carbon-1.0.0\Carbon\Import-Carbon.ps1'
is not recognized as the name of a cmdlet, function, script file, or
operable program. Check the spelling of the name, or if a path was
included, verify that the path is correct and try again.
Any suggestions about it?
Try:
. (Join-Path $PSPathCarbon 'Import-Carbon.ps1')
Or:
. "$PSPathCarbon\Import-Carbon.ps1"

dot-source failing oin powergui

I'im trying to dot-source a script file in PowerGui 3.0 , but all i get is ;
The term '.\PowerShell.Common.ps1' is not recognized as the name of a
cmdlet, function, script file, or operable program. Check the spel
ling of the name, or if a path was included, verify that the path is
correct and try again. At
D:\TFS\SharePoint\Dev\Deploy\AutoSPInstaller\SP2010\AutoSPInstaller\AutoSPInstallerFunctionsCustom.ps1:6
char:31
+ .\PowerShell.Common.ps1 <<<<
+ CategoryInfo : ObjectNotFound:
(.\PowerShell.Common.ps1:String) [], CommandNotFoundException
+ FullyQualifiedErrorId : CommandNotFoundException
And powerGui subsequently does not offer my script function within said file - in the context sensitive list in the parent script.
the file "PowerShell.Common.ps1" is in the same directory as AutoSPInstallerFunctionsCustom.ps1
Thank you for your assistance
To dot-source the file from PowerGUI's command line, make sure that your current working directory is at the script's directory. You can check this by typing $PWD at PowerGUI's command line.
To reference another script from a script you would do this:
# Get the current script's directory
$MyDir = Split-Path $MyInvocation.MyCommand.Definition
# Dot-source the external script by using the current script's directory
. "$MyDir\ScriptName.ps1"
Getting the script's directory ensures that even if your current working directory is not the same as the script's directory, you will be able to reference files relative to the script's location.
#Rynant is certainly correct in pointing out that the problem is you need to reference the script's directory rather than your current directory. However, it is important to note that his code solution is only partially correct; in fact, whether it works depends on where you call it!
A more robust solution is this:
function Get-ScriptDirectory
{
Split-Path $script:MyInvocation.MyCommand.Path
}
As it happens, I just wrote a detailed discussion analyzing this very point of correctly getting the script directory in another SO question. Rather than repeat my lengthy answer (complete with test vehicle and results matrix) I will provide this link.
This problem arises when you browse to the script you are working on from within PowerGUI.
Instead of changing the invocation paths to the other scripts you may prefer to run the script in-situ, i.e. with $PWD set to the directory of the script. This is most easily done by opening the script in PowerGUI through the Windows shell by using by the right-click context menu in Windows Explorer.

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"