Did the ampersand behavior change in Powershell 3.0? - powershell

I've gotten the following error when installing windirstat and ilmerge on Chocolatey. I'm suspicious that ampersand behavior changed in PowerShell 3.0.
Running powershell -NoProfile -ExecutionPolicy unrestricted -Command "& import-module -name 'C:\NuGet\chocolateyInstall\helpers\chocolateyInstaller.psm1'; & 'C:\NuGet\lib\ilmerge.2.10.526.4\tools\chocolateyInstall.ps1'". This may take awhile and permissions may need to be elevated, depending on the package.
ilmerge did not finish successfully. Boo to the chocolatey gods!
-----------------------
[ERROR] The expression after '&' in a pipeline element produced an invalid object. It must result in a command name, script block or Command
Info object.
-----------------------

The problem was not ampersand behavior I had to replace $oc = Get-Command 'Write-Host' | ?{$_.ModuleName -eq 'Microsoft.PowerShell.Utility'} with $oc = Get-Command 'Write-Host' -Module 'Microsoft.PowerShell.Utility' as well as make a similar replacement for a Write-Error wrapper.

How about starting PowerShell with the -version 1.0 or 2.0 parameter? Then run the above command and see if there is any difference.
At the commandline
PowerShell -version 2.0

Related

when running powershell --version it gives error

When i run
PS C:\Program Files\PowerShell\7> powershell.exe --version
it gives me below error.
At line:1 char:3
+ --version
+ ~
Missing expression after unary operator '--'.
At line:1 char:3
+ --version
+ ~~~~~~~
Unexpected token 'version' in expression or statement.
+ CategoryInfo : ParserError: (:) [], ParentContainsErrorRecordException
+ FullyQualifiedErrorId : MissingExpressionAfterOperator
Can you please help me to identify the issue.
I want to install AZURE POWERSHELL 7.0
There is no powershell --version option, in Powershell 5. Output of powershell -? is below. It looks like "-version" with one dash can run older versions of powershell.
powershell -?
PowerShell[.exe] [-PSConsoleFile <file> | -Version <version>]
[-NoLogo] [-NoExit] [-Sta] [-Mta] [-NoProfile] [-NonInteractive]
[-InputFormat {Text | XML}] [-OutputFormat {Text | XML}]
[-WindowStyle <style>] [-EncodedCommand <Base64EncodedCommand>]
[-ConfigurationName <string>]
[-File <filePath> <args>] [-ExecutionPolicy <ExecutionPolicy>]
[-Command { - | <script-block> [-args <arg-array>]
| <string> [<CommandParameters>] } ]
PowerShell[.exe] -Help | -? | /?
-PSConsoleFile
Loads the specified Windows PowerShell console file. To create a console
file, use Export-Console in Windows PowerShell.
-Version
Starts the specified version of Windows PowerShell.
Enter a version number with the parameter, such as "-version 2.0".
-NoLogo
Hides the copyright banner at startup.
-NoExit
Does not exit after running startup commands.
-Sta
Starts the shell using a single-threaded apartment.
Single-threaded apartment (STA) is the default.
-Mta
Start the shell using a multithreaded apartment.
-NoProfile
Does not load the Windows PowerShell profile.
-NonInteractive
Does not present an interactive prompt to the user.
-InputFormat
Describes the format of data sent to Windows PowerShell. Valid values are
"Text" (text strings) or "XML" (serialized CLIXML format).
-OutputFormat
Determines how output from Windows PowerShell is formatted. Valid values
are "Text" (text strings) or "XML" (serialized CLIXML format).
-WindowStyle
Sets the window style to Normal, Minimized, Maximized or Hidden.
-EncodedCommand
Accepts a base-64-encoded string version of a command. Use this parameter
to submit commands to Windows PowerShell that require complex quotation
marks or curly braces.
-ConfigurationName
Specifies a configuration endpoint in which Windows PowerShell is run.
This can be any endpoint registered on the local machine including the
default Windows PowerShell remoting endpoints or a custom endpoint having
specific user role capabilities.
-File
Runs the specified script in the local scope ("dot-sourced"), so that the
functions and variables that the script creates are available in the
current session. Enter the script file path and any parameters.
File must be the last parameter in the command, because all characters
typed after the File parameter name are interpreted
as the script file path followed by the script parameters.
-ExecutionPolicy
Sets the default execution policy for the current session and saves it
in the $env:PSExecutionPolicyPreference environment variable.
This parameter does not change the Windows PowerShell execution policy
that is set in the registry.
-Command
Executes the specified commands (and any parameters) as though they were
typed at the Windows PowerShell command prompt, and then exits, unless
NoExit is specified. The value of Command can be "-", a string. or a
script block.
If the value of Command is "-", the command text is read from standard
input.
If the value of Command is a script block, the script block must be enclosed
in braces ({}). You can specify a script block only when running PowerShell.exe
in Windows PowerShell. The results of the script block are returned to the
parent shell as deserialized XML objects, not live objects.
If the value of Command is a string, Command must be the last parameter
in the command , because any characters typed after the command are
interpreted as the command arguments.
To write a string that runs a Windows PowerShell command, use the format:
"& {<command>}"
where the quotation marks indicate a string and the invoke operator (&)
causes the command to be executed.
-Help, -?, /?
Shows this message. If you are typing a PowerShell.exe command in Windows
PowerShell, prepend the command parameters with a hyphen (-), not a forward
slash (/). You can use either a hyphen or forward slash in Cmd.exe.
EXAMPLES
PowerShell -PSConsoleFile SqlSnapIn.Psc1
PowerShell -version 2.0 -NoLogo -InputFormat text -OutputFormat XML
PowerShell -ConfigurationName AdminRoles
PowerShell -Command {Get-EventLog -LogName security}
PowerShell -Command "& {Get-EventLog -LogName security}"
# To use the -EncodedCommand parameter:
$command = 'dir "c:\program files" '
$bytes = [System.Text.Encoding]::Unicode.GetBytes($command)
$encodedCommand = [Convert]::ToBase64String($bytes)
powershell.exe -encodedCommand $encodedCommand
In powershell 7 there is a -version option with one dash, but the binary is called "pwsh".
pwsh -version
PowerShell 7.0.0

Get arguments passed to powershell.exe

Is there a way to determine, in a Profile script, what arguments were passed to the powershell executable?
Use-case
I'd like to check whether the WorkingDirectory parameter was set, before overriding it with my own cd in my user profile.
Attempts
I've made a few helpless attempts to get variable values from within the profile script, with no luck. None of them seem to give me any information about whether pwsh.exe was invoked with a -wd parameter or not:
echo $PSBoundParameters
echo $ArgumentList
echo (Get-Variable MyInvocation -Scope 0).Value;
To inspect PowerShell's own invocation command line, you can use:
[Environment]::CommandLine (single string)
or [Environment]::GetCommandLineArgs() (array of arguments, including the executable as the first argument).
These techniques also work on Unix-like platforms.
Caveat: As of PowerShell Core 7 (.NET Core 3.1), it is pwsh.dll, not pwsh[.exe] that is reported as the executable.
To check in your $PROFILE file if a working directory was specified on startup could look like this, though do note that the solution is not foolproof:
$workingDirSpecified =
($PSVersionTable.PSEdition -ne 'Desktop' -and
[Environment]::GetCommandLineArgs() -match '^-(WorkingDirectory|wd|wo|wor|work|worki|workin|working|workingd|workingdi|workingdir|workingdire|workingdirec|workingdirect|workingdirecto|workingdirector)') -or
[Environment]::CommandLine -match
'\b(Set-Location|sl|cd|chdir|Push-Location|pushd|pul)\b'
In PowerShell Core, a working directory may have been specified with the -WorkingDirectory / -wd parameter (which isn't supported in Windows PowerShell); e.g.,
pwsh -WorkingDirectory /
Note: Given that it is sufficient to specify only a prefix of a parameter's name, as long as that prefix uniquely identifies the parameter, it is necessary to also test for wo, wor, work, ...
In both PowerShell Core and Windows PowerShell, the working directory may have been set with a cmdlet call (possibly via a built-in alias) as part of a -c / -Command argument (e.g.,
pwsh -NoExit -c "Set-Location /")
Note: In this scenario, unlike with -WorkingDirectory, the working directory has not yet been changed at the time the $PROFILE file is loaded.
It is possible, but unlikely for the above to yield false positives; to use a contrived example:
pwsh -NoExit -c "'Set-Location inside a string literal'"
How about (powershell.exe or pwsh.exe?):
get-ciminstance win32_process | where name -match 'powershell.exe|pwsh.exe' |
select name,commandline

Jenkins Windows Batch Command Powershell Environment Variables

I have a PowerShell script to be executed as a build step in jenkins and need to pass environment variable to it
powershell -File .\Build.ps1 -Version $env:APP_VERSION_NUMBER
The APP_VERSION_NUMBER is an environment variable set by Version Number Plugin of Jenkins.
For some reason the -Version parameter is never set, and I see only $env:APP_VERSION_NUMBER in console log output.
Is this a syntax issue?
When you use the PowerShell CLI's -File parameter, the arguments passed to the script are treated as literals, so, given that you're invoking the command line not from PowerShell, $env:APP_VERSION_NUMBER is not expanded.
To force the target PowerShell process to evaluate the arguments, you must use -Command rather than -File:
powershell -Command .\Build.ps1 -Version $env:APP_VERSION_NUMBER
However, now that we know that you're invoking the command line via cmd.exe (a batch file) from Jenkins (a build step of type Execute Windows batch command), the simpler answer is indeed to let cmd.exe expand the environment-variable reference, using its %<envVarName>% syntax:
powershell -File .\Build.ps1 -Version "%APP_VERSION_NUMBER%"
Note: Enclosing the environment-variable reference in "..." isn't strictly necessary with a version number, but is a good habit to form, so that values with embedded spaces or other shell metacharacters are passed correctly too.
It turns out indeed its a syntax issue. The fix looks like the following
powershell -File ".\Build.ps1" -Version %APP_VERSION_NUMBER%

Error: "the term is not recognised as the name of a cmdlet"

I have written a basic script to execute and send an email with an attachment, I have tested this in PowerShell. However when I try to create this as a task scheduler I get the following error:
However my exact same code executes without issue in PowerShell.
This is my view in task scheduler:
What am I missing? I have set the execution policy so that is not an issue and I've tested my code and there is no issue there.
Use the -File parameter instead:
-File "C:\path\to\your.ps1"
PowerShell's call operator (&) works only inside PowerShell, so you would need to put it inside the argument string:
"& 'C:\path\to\your.ps1'"
While that would work too, it has certain disadvantages, most importantly that it will return only 0 (success) or 1 (failure) as the exit code, but not the actual exit code of the script.
Your argument needs to include the -Command parameter, not just the code you want to run. Also, your code to run needs to be a string, not raw Powershell code, or the command line will try to interpret it. Set the argument to:
-Command '&"C:\Users\Martyn\Documents\Powershell Scripts\Working.ps1"'
Or, you can try the -File parameter directly, although there are known issues with it:
-File "C:\Users\Martyn\Documents\Powershell Scripts\Working.ps1"
If anyone else is getting this error, you need to install ProcessMitigation into PowerShell before you can use it. By default, it's not there.
Steps to install:
Run Powershell with administrative rights.
Run Save-Module -Name ProcessMitigations -Path <path> command in PS to download the component. Provide actual path instead of to download.
Run Install-Module -Name ProcessMitigations in PS to install it.
More here.

Running PowerShell from RunOnce

I am trying to run a set of powershell commands during a template customization. These commands are injected into the RunOnce in the registry.
%SystemRoot%\system32\WindowsPowerShell\v1.0\powershell.exe -command &{Add-Type -Assembly System.Web; [Web.Security.Membership]::GeneratePassword(21,7) | Select-Object #{N="Group";E={"Test Group"}}, #{N="Username";E={"TestUser"}}, #{N="Password";E={$_}} | Export-Csv -Path C:\stuff\user.csv -NoTypeInformation}
I know that these commands work, as I can run them in a powershell console. I know that "%SystemRoot%\system32\WindowsPowerShell\v1.0\powershell.exe -command &{PSCODE}" is correct because other runonce commands will run correctly. I cannot figure out what part of my syntax is failing.
This could be a long trial and error session, to save you precious time, I suggest you use a script file instead of that long command:
%SystemRoot%\system32\WindowsPowerShell\v1.0\powershell.exe -File c:\script.ps1
Just want to add, that in order to run a sequence of commands you have to run it without quotes. At least only in this way it worked for me:
C:\Windows\System32\WindowsPowerShell\v1.0\powershell.exe -noexit Import-Module Hyper-V; Get-VMSwitch \"*Virtual*\" | Remove-VMSwitch -Force; New-VMSwitch -NetAdapterName \"Ethernet\" -Name \"VMNet\"