-2

Totally stuck here and have no idea what to do: I've got a multiple choice interactive Powershell script I'm putting together for the ops so they shave off a few minutes whenever they want to perform quick tasks on remote computers.

I've replaced all the code for all the other choices with just You have selected #, so I don't bore anyone with the rest of the script content, but choice 6 is driving me mad.

This is what I'm aiming for it to do, but can't get past the first bullet point yet:

  • Create new .vnc file
  • Add standard VNC protocol body of text into the file
  • Add $ComputerName after Host=
  • Launch the file

Problem is the below won't create the file at all; if copy/pasted directly into Powershell, it works, but it won't run in a script! Anyone know why that could be?

$commands = {
  function Show-Menu
  {
    param (
      [string]$Title = 'My Menu'
    )
    Clear-Host
    Write-Host "================ $Title ================"

    Write-Host "1: Press '1' (Description)."
    Write-Host "2: Press '2' (Description)."
    Write-Host "3: Press '3' (Description)."
    Write-Host "4: Press '4' (Description)."
    Write-Host "5: Press '5' (Description)."
    Write-Host "6: Press '6' To start a VNC Connection."
    Write-Host "Q: Press 'Q' to quit."
  }

  Show-Menu –Title 'My Menu'
  $selection = Read-Host "Please make a selection"
  switch ($selection)
  {
    '1' {
      "You have selected 1"
      sleep -seconds 2
    } '2' {
      "You have selected 2"
      sleep -seconds 2
    } '3' {
      "You have selected 3"
      sleep -seconds 2
    } '4' {
      "You have selected 4"
      sleep -seconds 2
    } '5' {
      "You have selected 5"
      sleep -seconds 2
    } '6' {
      $ComputerName = (Read-Host "ComputerName")
      {
        New-Item -Path "C:\Windows\Temp\$ComputerName.VNC"
        Set-Content "C:\Windows\Temp\$ComputerName.VNC" '
        [connection]
        host=$ComputerName
        port=5900
        [options]
        use_encoding_1=1
        copyrect=1
        viewonly=0
        fullscreen=0
        8bit=0
        shared=1
        belldeiconify=0
        disableclipboard=0
        swapmouse=0
        fitwindow=0
        cursorshape=1
        noremotecursor=0
        preferred_encoding=7
        compresslevel=-1
        quality=6
        localcursor=1
        scale_den=1
        scale_num=1
        local_cursor_shape=1'
      }
    } 'q' {
      #Closes the script
      return
    }
  }
  .$commands

}
&$commands
2
  • 1
    What happens when you try? You tell us "it won't run in a script" but what do you see when you try?
    – Reg Edit
    Commented Jul 19, 2020 at 14:39
  • 1
    please explain IN EXCRUCIATING DETAIL what you mean by won't run in a script.
    – Lee_Dailey
    Commented Jul 19, 2020 at 17:47

2 Answers 2

2

If copy/pasted directly into Powershell, it works, but it won't run in a script.

That sounds pretty much like an unsuitable execution policy. You can run Get-ExecutionPolicy to check on it. It probably returns Restricted.

To change that permanently, run an elevated PowerShell and execute Set-ExecutionPolicy RemoteSigned and confirm with y.

To change that temporarily just for the execution of your script, you can run it like this:

powershell -ExecutionPolicy Bypass -File .\ScriptFile.ps1

So, this how you can run your script from a script file. Besides that, there is another problem, already mentioned by @jfrmilner. In your 6th option your are defining another scriptblock by the additional curly braces:

...
} '6' {
      $ComputerName = (Read-Host "ComputerName")
      {
        # This just the definition of a scriptblock and will not be executed!
        # Instead, it will be sent to stdout.
      }
    } 'q' {
...

The definition itself will not run those lines. You have two possibilities to solve this problem:

  1. Omit the curly braces and thus do not define a scriptblock. The lines will be executed.
  2. Prefix the scriptblock by a . and it will be executed:
...
} '6' {
      $ComputerName = (Read-Host "ComputerName")
      .{
        # This is a scriptblock that will directly be executed!
      }
    } 'q' {
...
0

Ditto to what @Reg Edit and @Lee-Dailey are saying.

We can't see your screen.

Secondly, why would you expect...

&$commands

...this to work in a script?

$commands is not a .ps1 to execute, it is a scriptblock in your script.

You say you are pasting in powershell.exe console or the ISE or VSCode, it is supposed to work because you loaded the code and ran it from an existing PowerShell instance and the code was read in that instance.

So, unless this code is saved as commands.ps1, then &$commands is moot because the code is never loaded in a running or called PowerShell instance.

Also, that scriptblock is really not needed at all.

So, try this...

# VNCCommands.ps1
function Show-Menu
{
    param 
    (
        [string]$Title = 'My Menu'
    )

    Clear-Host
    $Banner = '='*16
    "$Banner $Title $Banner"

    "1: Press '1' (Description)."
    "2: Press '2' (Description)."
    "3: Press '3' (Description)."
    "4: Press '4' (Description)."
    "5: Press '5' (Description)."
    "6: Press '6' To start a VNC Connection."
    "Q: Press 'Q' to quit."
}

Show-Menu –Title 'My Menu'
$selection = Read-Host "Please make a selection"

switch ($selection)
{
    1 
    {
        "You have selected 1"
        sleep -seconds 2
    } 
    2 
    {
        "You have selected 2"
        sleep -seconds 2
    } 
    3 
    {
        "You have selected 3"
        sleep -seconds 2
    } 
    4 
    {
        "You have selected 4"
        sleep -seconds 2
    } 
    5 
    {
        "You have selected 5"
        sleep -seconds 2
    } 
    6 
    {
        $ComputerName = Read-Host -Prompt 'Enter a computer name: '
        If (-Not (Test-Path -Path "D:\temp\$ComputerName"))
        {New-Item -Path 'D:\Temp' -Name "$ComputerName.VNC" -ItemType File -Verbose}
        Else {Write-Warning -Message "D:\temp\$ComputerName.VNC creation failed"}
    } 
    'q' {return}
}

Execute ---

.\VNCCommands.ps1



# Results
<#
================ My Menu ================
1: Press '1' (Description).
2: Press '2' (Description).
3: Press '3' (Description).
4: Press '4' (Description).
5: Press '5' (Description).
6: Press '6' To start a VNC Connection.
Q: Press 'Q' to quit.
Please make a selection: 6
Enter a computer name: : test
VERBOSE: Performing the operation "Create File" on target "Destination: D:\Temp\test.VNC".


    Directory: D:\Temp


Mode                 LastWriteTime         Length Name
----                 -------------         ------ ----
-a----         19-Jul-20     17:14              0 test.VNC
#>
4
  • "$commands is not a .ps1 to execute, it is a scriptblock in your script." And why should he not be able to execute a scriptblock? This works: $commands = {Write-Host "Hello World!"};&$commands Commented Jul 20, 2020 at 5:20
  • You are running this interactively, not via a script. So, assigning a scriptblock and running interactively loads whatever you did, before running anything else. So, the second call works, because it is in the same session of the loaded code. You can only call .ps files from a cold start. You must load code before you it will execute, be it interactivel and calling it via powershell.exe. If you are already in a PowerShell session and id dwhat you did, then this [&$command] is moot, why use an external call operation (that call operator or start-process) to call internal loaded code.
    – postanote
    Commented Jul 20, 2020 at 5:56
  • Nonetheless, the response I gave solves your issue you say you are having without other steps.
    – postanote
    Commented Jul 20, 2020 at 5:58
  • I just put my example line into a script file and ran it non-interactively and it also worked. I don't see why it shouldn't. Commented Jul 20, 2020 at 6:05

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .