Cannot import module from Powershell started from Start-Process - powershell

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

How to call powershell script from other powershell script and script is assigned in the powershell object instead of the file

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

Start-Process powershell cannot find specified

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.

Powershell Start-Process with Splatting

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).

Call PowerShell script with arguments from another powershell script

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 !

Run Executable from Powershell script with parameters

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