The joys of software – PowerShell remoting edition

I was happily scripting in PowerShell and the script appeared to work. It remoted to a server, got that state of a few services, if they were running, how much memory they used, etc.

It used – very simplified

$Session = New-PSSession -ComputerName $server
Invoke-Command -Session $Session -ScriptBlock {#Remote code}

So after testing on a single server, I let it lose on all the production servers.  It worked for about 40% of them – the rest did not give a hoot about the script content.

Why?  No idea at the time.  So – what was the differences between the servers? They all had PowerShell 7.x installed, but some where 2016+ while others where 2012R2.  

Changing the remote script to simply retrieve the most current PS version config that the WinRM would provide. 

function Get-PSConfigs { 
    param (
        [String] $server
    Write-Host "--- $server --------------------------------------------------------------"
    $Session = New-PSSession -ComputerName $server
    if ($Session) {
        try {
            Invoke-Command -Session $Session -ArgumentList $server -ScriptBlock {
                Param ([string]$LocName)
                Get-PSSessionConfiguration | sort PSVersion -Descending | Select-Object -first 1
        finally {
            Remove-PSSession -Id $Session.Id

This revealed that all the servers that failed only offered PS version 4, and of those that worked, they only reported PS version 5.1.  Why!?  PS 7 was installed! Why didn’t the script run on PS 7?

So, after RTFM a lot, and experimenting a little, it turned out that to enable a configuration for remoting to PS 7, you have to start PWSH 7 with Administrator rights and run “Enable-PSRemoting”.

Only then will you have a PowerShell.7 configuration that you can use with New-PSSession.

function Get-PSSevenResults { 
    param (
        [string] $server
    $Session = New-PSSession -ComputerName $server -ConfigurationName PowerShell.7 
    if ($Session) {
        try {
            Invoke-Command -Session $Session -ArgumentList $server -ScriptBlock {
                Param ([string]$ServerName)
                # remote executed code here
        finally {
            Remove-PSSession -Id $Session.Id

Various error checking/handling removed for clarity

Fun fact – RDPing to 80+ servers, finding pwsh 7, starting it as admin, and running Enable-PSRemoting, is not really much fun at all.

PowerShell snippet: Get-Choice

You know when you want the user to make a choice, and you want him to type it out and get it right?

class Choice {    
    [string] $Key;
    [string] $Option;
    Choice($Key, $Option) {
        $this.Key = $Key
        $this.Option = $Option
  Read userinput and validate against choices
  Read userinput and validate against choices. Must match one of the keys. Not case sensitive.
 .Parameter Prompt
  Text to show when waiting for input
 .Parameter Choices
  List of Choice elements
 .Parameter NoHints
  Don't show list of hints for Choices
  $MyChoices = @(
      [Choice]::new('yes', 'Let me continue'), 
      [Choice]::new('no', 'I want to stop')
  $key = Get-Choice -Prompt "Do you want to continue?" -Choices $MyChoices
function Get-Choice {
    #    [OutputType([string])]
    param (
    $Hints = ""
    $Comma = ""
    $Opts = ""
    $Sep = ""
    $Choices | ForEach-Object {
        $Hints = $Hints + $Comma + '[' + $_.Key + '] ' + $_.Option
        $Comma = ', '
        $Opts = $Opts + $Sep + $_.Key 
        $Sep = '|'
    if (-not $NoHints) {
        Write-Host $Hints
    $pattern = $Opts.ToLower()
    $pattern = "¤¤$pattern¤¤" -replace "\|", "¤¤|¤¤"
    $ok = $false
    while (-not $ok) {
        [string]$userinput = (Read-Host -Prompt "$Prompt ($Opts)").ToLower()
        $userinput = ("¤¤$userinput¤¤" | Select-String -Pattern $pattern) -replace "¤¤" , ""
        $ok = ("$userinput" -ne "")
    return $userinput
} # Get-Choice

PowerShell snippet: Show-TextFile

You know those times that you need to show a log file or some text file?

  Open NotePad with the specified filename
  Open NotePad with the specified filename
 .Parameter FileName
  Name of text file to open
 .Parameter ScrollToEnd
  Scroll to the bottom of the opened file
 .Parameter Wait
  Wait for Notepad to close before continuing script
 .Parameter Kill 
  Kill Notepad after Timeout -Requires Wait
 .Parameter TimeOut 
  Timeout period in seconds - default = 300 - Requires Wait
  Show-TextFile -FileName 'C:\Some path\folder\filename.txt' -ScrollToEnd -Wait -Kill -TimeOut 30 
function Show-TextFile {
    param (
        [int]$TimeOut = 300
    if (Test-Path -Path $FileName) {
        $proc = Start-Process -FilePath 'NotePad.exe' -ArgumentList "$FileName" -NoNewWindow -PassThru
        if ($ScrollToEnd) { 
            # Use VBScript to send Ctrl-End keystroke to Notepad
            $wshell = New-Object -ComObject
            $title = Split-Path -path $FileName -Leaf
            Start-Sleep -seconds 0.5
            $wshell.AppActivate($title) | Out-Null
            $wshell.SendKeys('^{END}') | Out-Null
        if ($Wait) {
            Write-Host "To continue, close Notepad for '$FileName'"
            if (-not (Wait-Process -InputObject $proc -Timeout $TimeOut -ErrorAction SilentlyContinue)) {
                if (-not $Proc.HasExited) {
                    if ($Kill) {
                        Write-Host "Closed Notepad for $FileName"
                        Stop-Process -InputObject $proc -Force
                    } }
    else {
        Write-Warning "Show-TextFile -FileName not found: $FileName"
} # Show-TextFile

Did you know that you can enable VT100 terminal emulation in PowerShell as well as the Cmd window?

Did you know that you can enable VT100 terminal emulation in PowerShell as well as the Cmd window?

This will allow you to do adb shell to your Android device, and allows you to run “full screen” vi editing on any text file on the device.

#powershell #terminalemulation #vt100 #android

PowerShell Core 6.0 is a new edition of PowerShell that is cross-platform (Windows, macOS, and Linux), open-source,…

PowerShell Core 6.0 is a new edition of PowerShell that is cross-platform (Windows, macOS, and Linux), open-source, and built for heterogeneous environments and the hybrid cloud.

PowerShell Core is officially supported on the following platforms:

Windows 7, 8.1, and 10
Windows Server 2008 R2, 2012 R2, 2016
Windows Server Semi-Annual Channel
Ubuntu 14.04, 16.04, and 17.04
Debian 8.7+, and 9
CentOS 7
Red Hat Enterprise Linux 7
OpenSUSE 42.2
Fedora 25, 26
macOS 10.12+

Contributed, but not officially supported:

Arch Linux
Kali Linux
AppImage (works on multiple Linux platforms)

Experimental (unsupported) releases:

Windows on ARM32/ARM64
Raspbian (Stretch)