I have a powershell script: MyPSScript.ps1:
function DoFoo() {
$Powershell = "C:\windows\System32\WindowsPowerShell\v1.0\Powershell.exe"
$Command = "& C:\Temp\myscript.ps1"
Start-Process $Powershell -ArgumentList ("-noexit", "-noprofile", "-Command", $Command)
}
In myscript.ps1 I have:
Import-Module "C:\Temp\myscript2.ps1"
DoSomething()
In myscript2.ps1 I have:
function DoSomething() {
Write-Output "Hello World"
}
The problem is that myscript.ps1 is correctly executed, but the module is not imported as nothing is printed. Also, since I open the new powershell window using -noexit, I can type in it and if I try to call DoSomething, Powershell complains because it cannot find the command.
The funny thing is that, if I try to type manually the same import directive, then it imports the file corrently...
Are there any issues in importing a module from a Powershell which has been called from another process as I am doing?
Beside the typo I fixed (missing "=") in your question, there are several problems in the script you provided. The first one (MyPSScript.ps1) defines a function DoFoo but never calls it. The second one (myscript.ps1) wrongly calls DoSometing() with parentheses. If you fix those two problems, you'll see your "Hello World".
MyPSScript.ps1:
function DoFoo() {
$Powershell = "C:\windows\System32\WindowsPowerShell\v1.0\Powershell.exe"
$Command = "& C:\Temp\myscript.ps1"
Start-Process $Powershell -ArgumentList ("-noexit", "-noprofile", "-Command", $Command)
}
DoFoo
myscript.ps1:
Import-Module "C:\Temp\myscript2.ps1"
DoSomething
Powershell modules have a .psm1 file extension.
Rename your file "myscript2.ps1" to "myscript2.psm1", then it should work.
Related
I am writing a PowerShell script and I have another PowerShell script.
I know, we can use below code if it is stored in the path
$scriptPath = "D:\Ashish\powershell\script.ps1"
$argumentList = "asdf fgh ghjk"
$output =Invoke-Expression "& `"$scriptPath`" $argumentList"
but my PowerShell is stored in the object instead of a file. I am using the below code
$argumentList = "asdf fgh ghjk"
$logPath = "C:\AshishG\powershell\script21.txt"
$x = 'Write-Host "Hello script2" return "script2"' #This is my powershell script
//Write code here to call this script($x) with params and store the return value in the other object and also store the logs in $logpath
The one way could be to store the PowerShell to the script.ps1 but I think, there should be some way to call it from the PowerShell object itself?
Please share your suggestions.
Seems like you're looking for a script block:
$argumentList = "asdf fgh ghjk"
$logPath = "C:\AshishG\powershell\script21.txt"
$x = {
param($arguments, $path)
"Arguments: $arguments"
"Path: $path"
}
A script block can be executed using the call operator &:
& $x -arguments $argumentList -path $logPath
Or the dot sourcing operator .:
. $x -arguments $argumentList -path $logPath
.Invoke(..) method works too however it's not commonly used and not recommended in this context. See this answer for more information:
$x.Invoke($argumentList, $logPath)
Yet another option is to call the [scriptblock]::Create(..) method, if the script is stored in strings this is the recommended alternative over Invoke-Expression which should be avoided.. This is also very useful for example when we need to pass a function to a different scope. Thanks #mklement0 for the reminder on this one :)
$argumentList = "asdf fgh ghjk"
$logPath = "C:\AshishG\powershell\script21.txt"
$x = #'
"Arguments: $argumentList"
"Path: $logPath"
'#
& ([scriptblock]::Create($x))
# Or:
$scriptblock = [scriptblock]::Create($x)
& $scriptblock
Edit5: Adam's code works unless there are spaces in the path. That solution is at Powershell Opening File Path with Spaces
Edit4: Simplified further with a test for the path. Same Error.
If ($args[0] -eq "admin")
{
$TheScriptPath = "C:\Users\root\Desktop\script.ps1"
Test-Path ($TheScriptPath)
Start-Process "powershell -noexit" $TheScriptPath
}
Else { Write-Host "OK" }
Output when I call "powershell .\script.ps1 admin" is:
True
Start-Process : This command cannot be run due to the error: The system cannot find the file specified.
At C:\Users\root\Desktop\script.ps1:11 char:2
Edit3: Nevermind. Previous solution stopped working. Script is:
if ($args[0] -eq "admin)
{
$TheScriptPath = $myInvocation.MyCommand.Definition
Start-Process powershell -Verb runAs -Workingdirectory $PSScriptroot $TheScriptPath
exit
}
Write-Host "Ok"
Error when I call "powershell .\script.ps1 admin" is:
Start-Process : This command cannot be run due to the error: The system cannot find the file specified.
At C:\Users\root\Desktop\script.ps1:11 char:2
It's not even working when I hard-code the script path now, even with "-Verb runAs" removed.
Edit2: This is solved, I just can't accept my own answer for two days. Hopefully I remember to do that in case someone else comes along with this question.
Edit1: My script now reads:
If ($args[0] -eq "go")
{
$ThePath = $myInvocation.MyCommand.Definition
Start-Process powershell -Verb runAs $ThePath
Exit
}
Write-Host "OK"
It fails with the error below. However, if I hard-code the script path and write the script as:
If ($args[0] -eq "go")
{
Start-Process powershell -Verb runAs C:\Users\root\Desktop\script.ps1
Exit
}
Write-Host "OK"
It succeeds. I've also tried ""$myInvocation.MyCommand.Definition"" to no avail.
Original:
I have a powershell script that, at least in Windows 7, elevated the user and then ran the rest of the script. In Windows 10, however, it's giving me:
Exception calling "start" with "1" argument(s): "The system cannot find hte file specified"
At C:\Users\root\desktop\script.ps1:15 char:2
If ($True)
{
# We are not running "as Administrator" - so relaunch as administrator
# Create a new process object that starts PowerShell
$newProcess = new-object System.Diagnostics.ProcessStartInfo "PowerShell";
# Specify the current script path and name as a parameter
$newProcess.Arguments = $myInvocation.MyCommand.Definition;
# Indicate that the process should be elevated
$newProcess.Verb = "runas";
# Start the new process
[System.Diagnostics.Process]::Start($newProcess);
# Exit from the current, unelevated, process
exit
}
Write-Host "Ok"
The script exists at this path, as it actually attempting to invoke itself. I'm at a loss here.
I'm running Powershell v5.1.15063.1155 on Windows 10 (v10.0.15063 Build 15063). If I run the following:
$context = [Security.Principal.WindowsPrincipal] [Security.Principal.WindowsIdentity]::GetCurrent()
if (-not $context.IsInRole([Security.Principal.WindowsBuiltInRole]::Administrator)) {
Start-Process powershell -Verb runAs -ArgumentList $myInvocation.MyCommand.Definition
exit
}
Get-Date
Sleep -Seconds 4
You can try this as a workaround as it works for me.
To your question, I'd think something is wrong with the the ProcessStartInfo object you created ($newProcess). I've seen that error when the executable name supplied as a parameter can't be found. For example, if I run the following:
$newProcess = new-object System.Diagnostics.ProcessStartInfo "cocain";
$newProcess.Arguments = $myInvocation.MyCommand.Definition;
$newProcess.Verb = "runas";
[System.Diagnostics.Process]::Start($newProcess);
I get the error you described:
You're sure Powershell is in your path (where.exe powershell)? I know its a reach.
I want to call a "PS App Deployment Toolkit"-package (Link) from a PowerShell-Script with arguments.
The mentioned "PS App Deployment Toolkit"-package is a powershell-script, which I want to call with parameters. (Call a .ps1 from a .ps1)
I want to use splatting for the parameters.
I want to wait for the script to end.
I want to get the exit-code from the script.
Here is my code, which is not working:
$PSADToolKitInstallWrapper = "C:\Temp\MyPackage\PS-AppDeploy.ps1"
$PSADToolKitParameters = #{
"DeploymentType" = "Uninstall";
"DeployMode" = "Interactive";
"AllowRebootPassThru" = $True;
"TerminalServerMode" = $False;
"DisableLogging" = $False;
}
$InstallStatus = Start-Process -FilePath "PowerShell.exe" -ArgumentList $PSADToolKitInstallWrapper #PSADToolKitParameters -Wait -PassThru
Write-Host "Exit-Code: $( $InstallStatus.ExitCode )"
This Line would work fine, but I want to set the Parameters like in the example above:
$InstallStatus = Start-Process -FilePath "PowerShell.exe" -ArgumentList "$PSADToolKitInstallWrapper","-DeploymentType Install -DeployMode Silent -AllowRebootPassThru -TerminalServerMode" -Wait -PassThru
Could you please assist me to get this working?
Thank you!
I don't think you need to try so hard. Why run powershell.exe from inside a PowerShell script? You're already running PowerShell. Just run the command line you want:
$PSADToolKitParameters = #{
"DeploymentType" = "Uninstall"
"DeployMode" = "Interactive"
"AllowRebootPassThru" = $True
"TerminalServerMode" = $False
"DisableLogging" = $False
}
C:\Temp\MyPackage\PS-AppDeploy.ps1 #PSADToolKitParameters
If the path and/or filename to the script you want to run contains spaces, then call it with the invocation operator (&) and quote the filename; example:
& "C:\Temp\My Package\PS-AppDeploy.ps1" #PSADToolKitParameters
Checking the results of the script depends on what the script returns. If it returns an output object, then you can simply assign it:
$output = C:\Temp\MyPackage\PS-AppDeploy.ps1 ...
If the script runs an executable that sets an exit code, you check the value of the $LASTEXITCODE variable (this is analogous to the %ERRORLEVEL% dynamic variable in cmd.exe).
How do you call a PowerShell script which takes named arguments from within a PowerShell script?
foo.ps1:
param(
[Parameter(Mandatory=$true)][String]$a='',
[Parameter(Mandatory=$true)][ValidateSet(0,1)][int]$b,
[Parameter(Mandatory=$false)][String]$c=''
)
#stuff done with params here
bar.ps1
#some processing
$ScriptPath = Split-Path $MyInvocation.InvocationName
$args = "-a 'arg1' -b 2"
$cmd = "$ScriptPath\foo.ps1"
Invoke-Expression $cmd $args
Error:
Invoke-Expression : A positional parameter cannot be found that accepts
argument '-a MSFT_VirtualDisk (ObjectId =
"{1}\\YELLOWSERVER8\root/Microsoft/Windo...).FriendlyName -b 2'
This is my latest attempt - I've tried multiple methods from googling none seem to work.
If I run foo.ps1 from the shell terminal as ./foo.ps1 -a 'arg1' -b 2 it works as expected.
After posting the question I stumbled upon the answer. For completeness here it is:
bar.ps1:
#some processing
$ScriptPath = Split-Path $MyInvocation.InvocationName
$args = #()
$args += ("-a", "arg1")
$args += ("-b", 2)
$cmd = "$ScriptPath\foo.ps1"
Invoke-Expression "$cmd $args"
Here is something that might help future readers:
foo.ps1:
param ($Arg1, $Arg2)
Make sure to place the "param" code at the top before any executable code.
bar.ps1:
& "path to foo\foo.ps1" -Arg1 "ValueA" -Arg2 "ValueB"
That's it !
So I have a powershell script that is supposed to run an executable with an argument to pass to set which method I want to run, and I need to pass a parameter, which is a directory to a config file. So this is what I have
Start-Process -FilePath "C:\Program Files\MSBuild\test.exe" -ArgumentList /genmsi/f $MySourceDirectory\src\Deployment\Installations.xml
/f is the shortname and file is the long name for my attribute... I get an error in powershell telling me that a positional parameter cannot be found for /f or /file.
Any thoughts?
Try quoting the argument list:
Start-Process -FilePath "C:\Program Files\MSBuild\test.exe" -ArgumentList "/genmsi/f $MySourceDirectory\src\Deployment\Installations.xml"
You can also provide the argument list as an array (comma separated args) but using a string is usually easier.
Here is an alternative method for doing multiple args. I use it when the arguments are too long for a one liner.
$app = 'C:\Program Files\MSBuild\test.exe'
$arg1 = '/genmsi'
$arg2 = '/f'
$arg3 = '$MySourceDirectory\src\Deployment\Installations.xml'
& $app $arg1 $arg2 $arg3
I was able to get this to work by using the Invoke-Expression cmdlet.
Invoke-Expression "& `"$scriptPath`" test -r $number -b $testNumber -f $FileVersion -a $ApplicationID"
Just adding an example that worked fine for me:
$sqldb = [string]($sqldir) + '\bin\MySQLInstanceConfig.exe'
$myarg = '-i ConnectionUsage=DSS Port=3311 ServiceName=MySQL RootPassword= ' + $rootpw
Start-Process $sqldb -ArgumentList $myarg