Call PowerShell Script from PowerShell Script with multiple arguments - powershell

I know, this has been asked a few times but I cannot seem to get it working. Basically, I am using multiple ps1 files so I don't have to have a very large script, in this case, its two files (so far):
Migration-Main.ps1
Migration-Companies.ps1
I want to call Migration-Companies.ps1 from Migration-Main.ps1 using invoke expression but this seems to only work if there is only one parameter in the target script, in my case there are two:
param (
[parameter(mandatory=$false )]
[datetime]$CompanyDateCull,
[parameter(mandatory=$false )]
[string]$CompanyManagerCull
)
Write-Output $CompanyDateCull
So if I try to call the script like so:
Invoke-Expression "$Script_Companies -CompanyDateCull $CompanyDateCull -CompanyManagerCull "Fred""
I will get the following result:
Invoke-Expression : A positional parameter cannot be found that accepts argument 'Fred'.
At C:\Users\user\OneDrive\Scripts\Migrations\Imports\FastTrack-Migration-Main.ps1:282 char:1
+ Invoke-Expression "$Script_Companies -CompanyDateCull $CompanyDateCul ...
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ CategoryInfo : InvalidArgument: (:) [Invoke-Expression], ParameterBindingException
+ FullyQualifiedErrorId : PositionalParameterNotFound,Microsoft.PowerShell.Commands.InvokeExpressionCommand
But if i remove the second parameter
Invoke-Expression "$Script_Companies -CompanyDateCull $CompanyDateCull"
it works:
Saturday, 21 September 2013 12:00:00 AM
I have tried running the file with other commands as well, such as simply calling PowerShell.exe:
PowerShell.exe -file $Script_Companies -CompanyDateCull $CompanyDateCull -CompanyManagerCull $CompanyManagerCull
But this stops any of my dot sourced functions from being accessible to the script being called, which is a requirement.
Any help would be much appreciated.

For the first query you need escape the double quotes with backtick(`) :
Invoke-Expression "$Script_Companies -CompanyDateCull $CompanyDateCull -CompanyManagerCull `"Fred`""

Related

Hand over multiline string as script Paramter in Powershell

The setup
In a powershell script I have written I use a Multiline string like the following:
$MLINE_VARIABLE = "*file1
- change1
- change2
*file_2
- change1
- change2
*file-3
- change1
- change2"
Since this string is saved as a variable I wanted to give the script that variable as parameter:
param(
[string]$NORMAL_STRING,
[string]$MULTILINE_STRING
)
echo $NORMAL_STRING
echo $MULTILINE_STRING
run the script
I am fairly new to powershell but feel quite well with bash scripts. I tested this script with multiple inputs. here are the results:
powershell .\test.ps1 -NORMAL_STRING "This is a Normal String!" -MULTILINE_STRING $MLINE_VARIABLE
The first run resultet in following long error Message (Error Message was in german and I translated the first occurance of an error):
powershell : In line:2 char:4
In line:1 char:1
+ powershell .\small_test.ps1 -NORMAL_STRING "THIS IS A NORMAL STRING!" ...
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ CategoryInfo : NotSpecified: (In line:2 char:4:String) [], RemoteException
+ FullyQualifiedErrorId : NativeCommandError
+ - change1
+ ~
Missing expression after unary operator '-'.
In line:2 char:5
+ - change1
+ ~~~~~~~
Unexpected token "change1" in expression or statement.
In line:3 char:4
.
.
.
Not all analytical errors were reported. Correct the reported errors and try again.
+ CategoryInfo : ParserError: (:) [], ParentContainsErrorRecordException
+ FullyQualifiedErrorId : MissingExpressionAfterOperator
The Next test I didn't used the multiline string for a sanity check:
powershell .\test.ps1 -NORMAL_STRING "This is a Normal String!"
I realized that the script is working, but only showing the first 2 entries of the normal string:
>> This
>> is
I assume that somehow the NORMAL_STRING was set to "This" and the missing parameter MULTILINE_STRING was set to "is".
So to test if the scripts works as intended I changed the Parameter -NORMAL_STRING "This_is_a_normal_Parameter" and instead of using the $MULTILINE_STRING as parameter I set it inside the script.
What I need
How could I successful hand over this Multiline Parameter without messing up all the variables?
Without using parameter -File, what follows after powershell.exe is regarded as if it were a -Command, which executes the specified commands (and any parameters) as though they were typed at the PowerShell command prompt.
In this case however, you want it to run another PowerShell script, stored in a file.
When used with -File <PathToTheScript>, the script runs in the local scope ("dot-sourced"), so that the functions and variables that the script creates are available in the current session.
All values typed after the File parameter are interpreted as the script file path and parameters passed to that script.
This means that changing your code to
powershell -File '.\test.ps1' -NORMAL_STRING "This is a Normal String!" -MULTILINE_STRING $MLINE_VARIABLE
would work as intended

PowerShell Error - Missing expression after unary operator '-'

I have two PowerShell scripts. One is for uninstalling and installing a SharePoint 2010 solution on the SharePoint server. The other calls this script with two commands, one for the uninstall and one for the install. These are not scripts I wrote, but I have inherited them.
Here is the script that calls the install / uninstall script (I've removed some parameters to simplify for troubleshooting):
& 'C:\Users\username\Documents\setup.ps1' -InstallOrUninstall '/UNINSTALL'
& 'C:\Users\username\Documents\setup.ps1' -InstallOrUninstall '/INSTALL'
Stripped down to almost nothing for the purpose of testing, here is the "setup.ps1" script:
param ($InstallOrUninstall,
$SiteURL,
$WebURL,
[switch]$ignoreFeatures,
[switch]$thisAppDomain )
if (-not $thisAppDomain)
{
Write-Host "Invoking script in a new app domain" -foregroundcolor yellow
Write-Host $MyInvocation.Line
powershell.exe -Version 2 -Command $MyInvocation.Line -thisAppDomain
return;
}
Write-Host "In Body"
Write-Host $MyInvocation.Line
Running the first script returns an error from the first command, but not from the second. The error is:
powershell.exe : - : Missing expression after unary operator '-'.
At C:\Users\username\Documents\setup.ps1:11 char:6
+ powershell.exe -Version 2 -Command $MyInvocation.Line -thisAppDo ...
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ CategoryInfo : NotSpecified: (- : Missing exp...y operator '-'.:String) [], RemoteException
+ FullyQualifiedErrorId : NativeCommandError
+ CategoryInfo : ParserError: (-:String) [], ParentContainsErrorRecordException
+ FullyQualifiedErrorId : MissingExpressionAfterOperator
I believe the reason the install / uninstall script is resending the command for "Version 2" is because of an issue with using PowerShell past Version 2 with SharePoint 2010 (as outlined here). However, I don't understand why only the first line fails. The second command also enters the if statement, but does not error.
If I remove the second line, and only call the setup.ps1 one time, the script that calls the install / uninstall script succeeds.
A nice little brain-teaser. Apparently, $MyInvocation.Line contains the full line, including the newline / linebreak at the end. So, -thisAppDomain is not interpreted as a parameter, but the beginning of a new expression starting with -. This is also, why it works if you remove the 2nd line, because then you do not have a line break at the end.
To reproduce this error, try:
powershell.exe -Version 2 -Command "`r`n-thisAppDomain"
Note that in newer versions the parsing algorithm was obviousy modified and the error message is different. Omit the -Version 2 switch and you likely get:
The term "-thisAppDomain" is not recognized as the name of a cmdlet, function, script file, or operable program...
One simple way to resolve this would be to .Trim() (or .TrimEnd()) the command:
powershell.exe -Version 2 -Command $MyInvocation.Line.Trim() -thisAppDomain
I need to add though, that you should reconsider what your actual problem is, and if your solution is actually the best way to solve it. Have a look at jobs for example.
As marsze said: It is not interpreted as a parameter, but the beginning of a new expression starting with -. This is also, why it works if you remove the 2nd line, because then you do not have a line break at the end.

Initialize google chrome by calling a variable

This is what I had in mind:
$chrome= (Start-Process "chrome.exe" "chrome:\\newtab")
$chrome
Pushing enter at the end of the first line loads chrome instantly.
But instead of typing in "Start-Process......." each time, there must be a way to get this simple code assigned to something that is faster to type.
When running the second line of the code it just does nothing.
Any ideas?
By the way, I read this and this questions on this site but I still don't understand how to code this properly. I'm a total newcomer to this.
This is an edit in response to the answer given by #vonPryz
PS C:\>function Launch-Chrome {Start-Process "chrome.exe" "chrome:\\newtab"}
Get-Process : A positional parameter cannot be found that accepts argument 'Launch-Chrome'.
At line:1 char:1
+ PS C:\>function Launch-Chrome {Start-Process "chrome.exe" "chrome:\\n ...
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ CategoryInfo : InvalidArgument: (:) [Get-Process], ParameterBindingException
+ FullyQualifiedErrorId : PositionalParameterNotFound,Microsoft.PowerShell.Commands.GetProcessCommand
PS C:\>Launch-Chrome
PS : Cannot find a process with the name "C:\>Launch-Chrome". Verify the process name and call the cmdlet again.
At line:1 char:1
+ PS C:\>Launch-Chrome
+ ~~~~~~~~~~~~~~~~~~~~
+ CategoryInfo : ObjectNotFound: (C:\>Launch-Chrome:String) [Get-Process], ProcessCommandException
+ FullyQualifiedErrorId : NoProcessFoundForGivenName,Microsoft.PowerShell.Commands.GetProcessCommand
Tried it in powershell 2 and 1 but still doesn't work sadly.
There are quite a few ways to achieve this.
The first one is to create a function that launches Chrome. Like so,
PS C:\>function Launch-Chrome {Start-Process "chrome.exe" "chrome:\\newtab"}
PS C:\>Launch-Chrome
# A new Chrome window appears!
Save the function in your Powershell profile so that it'll be included on each new session. This might be the simplest solution, so try it first.
Another one is to create a script file that contains the function. Load the script either by dot-sourcing it on a session, or in your Powershell profile. If you need complex scripts, it might be worthwhile to maintain the scripts on separate path and just use profile to load those.
Third one is to create a Powershell module that contains the function. This is the most complex alternative out of the three solutions.
I fixed it.
PS C:\function L-C {Start-Process "chrome.exe" "chrome:\\newtab"}
PS C:\ L-C
# Chrome window opens

Set window title when running "start powershell" in powershell not working?

The following command works in CMD (How to start powershell with a window title?).
start powershell -NoExit -command "$Host.UI.RawUI.WindowTitle = 'bits'"
But it doesn't work in Powershell.
PS C:\> start powershell -noexit -command "$Host.UI.RawUI.WindowTitle = 'test'; read-host"
Start-Process : A parameter cannot be found that matches parameter name 'noexit'.
At line:1 char:18
+ start powershell -noexit -command "$Host.UI.RawUI.WindowTitle = 'test ...
+ ~~~~~~~
+ CategoryInfo : InvalidArgument: (:) [Start-Process], ParameterBindingException
+ FullyQualifiedErrorId : NamedParameterNotFound,Microsoft.PowerShell.Commands.StartProcessCommand
The following command can open a new powershell window.
start powershell "$Host.UI.RawUI.WindowTitle = 'test'; read-host"
However, the new window shows the following error message and the title is not set.
System.Management.Automation.Internal.Host.InternalHost.UI.RawUI.WindowTitle : The term
'System.Management.Automation.Internal.Host.InternalHost.UI.RawUI.WindowTitle' 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.
At line:1 char:1
+ System.Management.Automation.Internal.Host.InternalHost.UI.RawUI.Wind ...
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ CategoryInfo : ObjectNotFound: (System.Manageme...wUI.WindowTitle:String) [], CommandNotFoundException
+ FullyQualifiedErrorId : CommandNotFoundException
Bacon Bits' helpful answer explains that start in cmd.exe means something different than in PowerShell.
Use Start-Process as follows to get the desired result; note that powershell implicitly binds to parameter -FilePath, whereas the ,-separated arguments starting with -NoExit bind implicitly to the -ArgumentList (-Args) parameter, which accepts an array of strings:
# In PowerShell, `start` is an alias for `Start-Process`
start powershell '-NoExit', '-command', "`$Host.UI.RawUI.WindowTitle = 'bits'"
In paticular, --prefixed pass-through arguments must be quoted so that they're not mistaken for Start-Process's own parameters.
Also note the ` preceding the $ in $Host, which prevents up-front interpolation of $Host by the calling PowerShell instance.
You could also use '$Host.UI.RawUI.WindowTitle = ''bits''', a single-quoted literal string with embedded single quotes escaped as ''.
Important:
While passing arguments as an array to -ArgumentList is conceptually the best approach, it is unfortunately ill-advised due to a long-standing bug in Start-Process, still present as of this writing (v7.1) - see GitHub issue #5576.
For now, using a single string comprising all arguments, enclosed in embedded "..." quoting as necessary, is the only generally robust approach. As discussed in the linked GitHub issue, an -ArgumentArray parameter that supports robust array-based argument passing may be introduced in the future.
In the case at hand this means the following, as suggested by PetSerAl in a comment on the question:
Start-Process powershell '-NoExit -command "$Host.UI.RawUI.WindowTitle = ''bits''"'
Note the single-quoting_ ('...') of the overall argument-list string, which then necessitates escaping the embedded single quotes - those that PowerShell should see as part of the command - as ''.
In Command Prompt, start is the start internal command. In Windows Powershell, start is an alias for Start-Process, which does something similar but isn't identical.
Try running this:
powershell -NoExit -command "`$Host.UI.RawUI.WindowTitle = 'bits'"
Here's another way, while avoiding the dollar sign. The double quotes have to be on the outside, so that bits stays quoted.
start powershell "-noexit (get-variable host).value.ui.rawui.windowtitle = 'bits'"
You can always avoid these quoting issues putting the command in a file.
start powershell '-noexit .\window.ps1'
start powershell with the command option for setting the window title did not work for me. Maybe because I want to open another powershell with a ps1 file. so in the other ps1 file I added the first line as below,
(Get-Host).ui.RawUI.WindowTitle='TEST TEST'
and it worked like a charm....
If you add this to your powershell profile.ps1 you can get the window title to show the current running script and if you are just opening a window with no script then 'pwsh' will be displayed.
Will be systematic with no need to add a line on top of each script. The other answers
combined with $MyInvocation.MyCommand seem to give the name of the profile.ps1 instead when running a script from the context menu.
This can also be tweaked to change the result.
[console]::title = Split-Path -Leaf ([Environment]::GetCommandLineArgs()[-1]).Replace('pwsh.dll','pwsh')
Works on both PS 5 and 7 . For ver. 5 replace pwsh.dll by powershell.exe

How to use an environment variable in PowerShell console?

I have an environment variable named GOPATH. In old style command shell I could run the command %GOPATH%\bin\hello like this:
Is there an equivalently simple command in Windows PowerShell?
EDIT
I am not trying to print the environment variable. I am trying to USE it.
The variable is set correctly:
C:\WINDOWS\system32> echo $env:gopath
C:\per\go
Now I want to actually use this in a command line call, and it fails:
C:\WINDOWS\system32> $env:gopath\bin\hello
At line:1 char:12
+ $env:gopath\bin\hello
+ ~~~~~~~~~~
Unexpected token '\bin\hello' in expression or statement.
+ CategoryInfo : ParserError: (:) [], ParentContainsErrorRecordException
+ FullyQualifiedErrorId : UnexpectedToken
Use $env:[Variablename]
For example:
$env:Appdata
or
$env:COMPUTERNAME
using your example:
$env:GOPATH
To use this to execute a script use
& "$env:GOPATH\bin\hello"
Using an environment variable in a path to invoke a command would require either dot notation or the call operator. The quotation marks expand the variable and the call operator invokes the path.
Dot Notation
. "$env:M2_Home\bin\mvn.cmd"
Call Operator
& "$env:M2_Home\bin\mvn.cmd"
One solution is to use start-process -NoNewWindow to run it.
C:\windows\system32> start-process -nonewwindow $env:gopath\bin\hello.exe
C:\windows\system32Hello, Go examples!
>
This is much more verbose obviously and puts the command prompt at an odd looking prompt: >. But it does work.