0

invoke-expression 'cmd /c start pwsh -NoExit -Command { cd -path $env:homedrive$env:homepath/Documents/MySillyFolder; $host.UI.RawUI.WindowTitle = "A Silly Little Title"; color -background "red"; }'

#< CLIXML System.Management.Automation.ErrorRecordSystem.ObjectCannot find path 'C:\Users\Administrator\Documents\MySillyFolder' because it does not exist.System.Management.Automation.ItemNotFoundExceptionSystem.Management.Automation.SessionStateExceptionSystem.Management.Automation.RuntimeExceptionSystem.SystemExceptionSystem.ExceptionSystem.ObjectSystem.Management.Automation.ItemNotFoundException: Cannot find path 'C:\Users\Administrator\Documents\MySillyFolder' because it does not exist.x000D__x000A at System.Management.Automation.LocationGlobber.ExpandMshGlobPath(String path, Boolean allowNonexistingPaths, PSDriveInfo drive, ContainerCmdletProvider provider, CmdletProviderContext context)x000D__x000A at System.Management.Automation.LocationGlobber.ResolveDriveQualifiedPath(String path, CmdletProviderContext context, Boolean allowNonexistingPaths, CmdletProvider& providerInstance)x000D__x000A at System.Management.Automation.LocationGlobber.GetGlobbedMonadPathsFromMonadPath(String path, Boolean allowNonexistingPaths, CmdletProviderContext context, CmdletProvider& providerInstance)x000D__x000A at System.Management.Automation.SessionStateInternal.SetLocation(String path, CmdletProviderContext context, Boolean literalPath)x000D__x000A at System.Management.Automation.PathIntrinsics.SetLocation(String path, CmdletProviderContext context, Boolean literalPath)x000D__x000A at Microsoft.PowerShell.Commands.SetLocationCommand.ProcessRecord()Cannot find path 'C:\Users\Administrator\Documents\MySillyFolder' because it does not exist.C:\Users\Administrator\Documents\MySillyFolderDrivefalseSystem.Collections.ObjectModel.Collection`1[System.String] ExpandMshGlobPath(System.String, Boolean, System.Management.Automation.PSDriveInfo, System.Management.Automation.Provider.ContainerCmdletProvider, System.Management.Automation.CmdletProviderContext) at System.Management.Automation.LocationGlobber.ExpandMshGlobPath(String path, Boolean allowNonexistingPaths, PSDriveInfo drive, ContainerCmdletProvider provider, CmdletProviderContext context)x000D__x000A at System.Management.Automation.LocationGlobber.ResolveDriveQualifiedPath(String path, CmdletProviderContext context, Boolean allowNonexistingPaths, CmdletProvider& providerInstance)x000D__x000A at System.Management.Automation.LocationGlobber.GetGlobbedMonadPathsFromMonadPath(String path, Boolean allowNonexistingPaths, CmdletProviderContext context, CmdletProvider& providerInstance)x000D__x000A at System.Management.Automation.SessionStateInternal.SetLocation(String path, CmdletProviderContext context, Boolean literalPath)x000D__x000A at System.Management.Automation.PathIntrinsics.SetLocation(String path, CmdletProviderContext context, Boolean literalPath)x000D__x000A at Microsoft.PowerShell.Commands.SetLocationCommand.ProcessRecord()Cannot find path 'C:\Users\Administrator\Documents\MySillyFolder' because i

M Thompson
  • 25
  • 2

1 Answers1

0

Why are you not following the Help file specifics?

https://learn.microsoft.com/en-us/powershell/module/microsoft.powershell.core/about/about_pwsh?view=powershell-7.1

pwsh -Command {Get-WinEvent -LogName security}

In cmd.exe, there is no such thing as a script block (or ScriptBlock type), so the value passed to Command will always be a string. You can write a script block inside the string, but instead of being executed it will behave exactly as though you typed it at a typical PowerShell prompt, printing the contents of the script block back out to you.

A string passed to Command is still executed as PowerShell code, so the script block curly braces are often not required in the first place when running from cmd.exe. To execute an inline script block defined inside a string, the call operator & can be used:

pwsh -Command "& {Get-WinEvent -LogName security}"

If the value of Command is a string, Command must be the last parameter for pwsh, because all arguments following it are interpreted as part of the command to execute.

When called from within an existing PowerShell session, the results are returned to the parent shell as deserialized XML objects, not live objects. For other shells, the results are returned as strings.

If the value of Command is -, the command text is read from standard input. You must redirect standard input when using the Command parameter with standard input. For example:

Firstly this entire line has issues

invoke-expression 'cmd /c start pwsh -NoExit -Command {cd -path $env:homedrive$env:homepath/Documents/MySillyFolder;$host.UI.RawUI.WindowTitle = "A Silly Little Title"; color -background "red";}'

1 - Invoke-Expression

Invoke-Expression considered harmful | PowerShell Team: https://devblogs.microsoft.com/powershell/invoke-expression-considered-harmful

InfoSec Handlers Diary Blog: https://isc.sans.edu/diary/Did+You+Spot+%22Invoke-Expression%22%3F/26762

So, in a PowerShell session, use the call operator & or Invoke-Command or Start-Process to run executables. See details here:

• PowerShell: Running Executables: https://social.technet.microsoft.com/wiki/contents/articles/7703.powershell-running-executables.aspx

2 - this is not valid, and Windows does not use a forward slash for file system paths.

cd -path $env:homedrive$env:homepath/Documents/MySillyFolder
# Results
<#
 $env:homedrive$env:homepath
At line:1 char:15
+ $env:homedrive$env:homepath
+               ~~~~~~~~~~~~~
Unexpected token '$env:homepath' in expression or statement.
#>

these are two separate things.

$env:homedrive
# Results
<#
C:
#>

$env:homepath
# Results
<#
\Users\WDAGUtilityAccount
#>

You get the path you are after using the right $env variable

$env:USERPROFILE
# Results
<#
C:\Users\WDAGUtilityAccount
#>

So this...

cmd /c start pwsh -NoExit -Command {cd -path $env:homedrive$env:homepath/Documents/MySillyFolder

...becomes this...

cmd /c start pwsh -NoExit -Command {cd -path $env:USERPROFILE\Documents\MySillyFolder

3 - This is not valid at all

color -background "red"

4 - Why are you in Powershell, starting cmd.exe to start Powershell? That is redundant. In a PS instance to start cmd.exe to start another PS Instance.

cmd /c "start pwsh"

3- if this is in the shell, then the semi-colon concatenation is fine, but pointless in a script, also, since you are using variables, they must be expanded using double quotes, not single. Simple strings use single quotes.

So, in the cmd.exe shell, this

pwsh -NoExit -NoProfile -NoLogo -Command "& {cd -path "$env:USERPROFILE\Documents\MySillyFolder";$host.UI.RawUI.WindowTitle = 'A Silly Little Title';$host.UI.RawUI.ForegroundColor = 'Red'}"

More specifically, always check if the target exists before trying to do anything to/with it. So, this:

pwsh -NoExit -NoProfile -NoLogo -Command "& {If(Test-Path -Path "$env:USERPROFILE\Documents\MySillyFolder"){cd -path "$env:USERPROFILE\Documents\MySillyFolder";$host.UI.RawUI.WindowTitle = 'A Silly Little Title';$host.UI.RawUI.ForegroundColor = 'Red';'Hello World'}Else{Write-Warning -Message 'Path not found'}}"

As a script:

# Save this as Start-Script.ps1
If(Test-Path -Path "$env:USERPROFILE\Documents\MySillyFolder")
{
    Set-Location -path "$env:USERPROFILE\Documents\MySillyFolder"
    $host.UI.RawUI.WindowTitle     = 'A Silly Little Title'
    $host.UI.RawUI.ForegroundColor = 'Red'
    'Hello World'
}
Else{Write-Warning -Message 'Path not found'}

pwsh -NoExit -NoProfile -NoLogo C:\Scripts\Start-Script.ps1

Udpdate As for this comment:

What I was really trying for is to get a new script to open up in a new window and be able to pass those variables with a job. But I am finding this to be very difficult. It seems powershell does not like to pass a local variable in a job.

This is really a straightforward thing via PowerShell. Yet as with using local variables in the PSRemote session, variables have scope per session. AS detailed here:

https://learn.microsoft.com/en-us/powershell/module/microsoft.powershell.core/about/about_scopes?view=powershell-7.1

As also noted on SO, in these Q&A's

# Powershell pass variable to start-job
# Use the -ArgumentList parameter on Start-Job e.g.:
Start-Job -Scriptblock {param($p) "`$p is $p"} -Arg 'Server1'

or $Servername = 'Server1' Start-Job { "Target: " + $using:ServerName } | Receive-Job -Wait -AutoRemoveJob

Or this one:

Start-Job -ScriptBlock {& $using:command}
postanote
  • 15,138
  • 2
  • 14
  • 25
  • What I was really trying for is to get a new script to open up in a new window and be able to pass those variables with a job. But I am finding this to be very difficult. It seems powershell does not like to pass a local variable in a job. I was trying to use that as an example. But I failed miserably. I am running pester tests and it's an uninstall check for counters but they remain in the current powershell window. So My idea was to open a new powershell window and send the command for the pester test with some variables. But Powershell has a problem with this. Thanks for all your thoughts. – M Thompson Mar 31 '21 at 22:04
  • @/m-thompson, you did not mention jobs in your original post, so no one would have known that was what you also wanted. Anyway... see my update for you relative to this ask. – postanote Apr 01 '21 at 07:53
  • I failed miserably this was my first post and I think I got it now. Thanks for the help. – M Thompson Apr 01 '21 at 17:37