Converting SecureString to Text

It can be very useful to be able to convert an encrypted SecureString back to a plain text. This way, for example, you can use PowerShell’s “masked input” features. Simply ask for a SecureString, and PowerShell takes care of masking the user input. Next, take the SecureString and turn it into a plain text so you can use it internally for whatever you like:

function Convert-SecureStringToText
{
  param
  (
    [Parameter(Mandatory,ValueFromPipeline)]
    [System.Security.SecureString]
    $Password
  )
  
  process
  {
    $BSTR = [System.Runtime.InteropServices.Marshal]::SecureStringToBSTR($Password)
    [System.Runtime.InteropServices.Marshal]::PtrToStringAuto($BSTR)
  }
}

$password = Read-Host -Prompt 'Enter password' -AsSecureString
$plain = Convert-SecureStringToText -Password $password

"You entered: $plain"

If you wonder why it is possible to turn a SecureString into a plain text in the first place, then be aware: SecureStrings protect string content only for 3rd party, i.e. “man-in-the-middle” attacks. It is never a protection for the person that actually entered the secret.

This also illustrates why working with credentials can be risky. When a script asks for a credential, the script can always get to the entered secret password:

$cred = Get-Credential -UserName $env:USERNAME -Message 'Enter your password'
$plain = Convert-SecureStringToText -Password $cred.Password
"You entered: $plain" 

In fact, with credential objects, it is even more trivial to get back the entered password because it has a built-in method to do just this:

$cred = Get-Credential -UserName $env:USERNAME -Message 'Enter your password'
$plain = $cred.GetNetworkCredential().Password
"You entered: $plain" 

When a script asks for a credential, make sure you trust the script (author).


Twitter This Tip! ReTweet this Tip!

Embedding Binaries (Pictures, DLLs) in PowerShell Scripts

If your script requires external binary resources such as picture files or DLLs, you can of course ship them together with your script. You could, however, also embed these binaries as text in your script files:

  • Read the binary files as bytes
  • Save the bytes as Base64-encoded strings

This way, your script can then read the Base64-encoded binaries from a text variable, turn the data back into bytes, and write them back into temporary files.

Here are two simple functions that illustrate the concept:

function Convert-BinaryToText
{
  param
  (
    [Parameter(Mandatory)]
    [string]
    $Path
  )

  $Bytes = [System.IO.File]::ReadAllBytes($Path)
  [System.Convert]::ToBase64String($Bytes)
}

function Convert-TextToBinary
{
  param
  (
    [Parameter(Mandatory)]
    [string]
    $Text,
    
    [Parameter(Mandatory)]
    [string]
    $OutputPath
  )

  $Bytes = [System.Convert]::FromBase64String($Text)
  [System.IO.File]::WriteAllBytes($OutputPath, $Bytes)
}

Convert-BinaryToText takes a path to any file and returns the Base64-encoded string. Convert-TextToBinary does the opposite: submit the Base64-encoded string plus a destination path, and the function recreates the binary file.

Note that saving a binary file as Base64-string isn’t exactly space conserving. Your script is likely to grow in size beyond the original binary file size. However, even though the Base64-encoded strings are large, PowerShell handles them well, and extracting a binary file from Base64-encoded strings is very fast.


Twitter This Tip! ReTweet this Tip!

Built-In SSH support in Windows 10

In October 2018, a Windows 10 update added built-in SSH support to Windows 10. From now on, Windows 10 ships with a command-line tool called “ssh”. You can use it from within PowerShell to connect to other devices (including IoT, Raspberry Pi, etc) without the need for 3rd party tools:

 
PS> ssh
usage: ssh [-46AaCfGgKkMNnqsTtVvXxYy] [-B bind_interface]
           [-b bind_address] [-c cipher_spec] [-D [bind_address:]port]
           [-E log_file] [-e escape_char] [-F configfile] [-I pkcs11]
           [-i identity_file] [-J [[email protected]]host[:port]] [-L address]
           [-l login_name] [-m mac_spec] [-O ctl_cmd] [-o option] [-p port]
           [-Q query_option] [-R address] [-S ctl_path] [-W host:port]
           [-w local_tun[:remote_tun]] destination [command] 
PS> 
 

Twitter This Tip! ReTweet this Tip!

Playing with Latest PowerShell Core Version

In the previous tip we illustrated how you can download a PowerShell script which automatically downloads the latest version of PowerShell Core.

This script supports a number of parameters. By default, it fetches the latest (stable) production version. If you’d like to play with the latest version including preview versions, use the -Preview parameter. And, if you’d like to install it using an MSI package, add -MSI.

You don’t necessarily have to save the script to a file. Instead, you can directly execute the downloaded script file and invoke it with Invoke-Expression. This cmdlet is considered risky though because it directly executes any code you submit, without a chance for you to review the code first.

Here is a sample line that downloads the latest PowerShell Core version using MSI:

Invoke-Expression -Command "& { $(Invoke-RestMethod https://aka.ms/install-powershell.ps1) } -UseMSI -Preview"

Twitter This Tip! ReTweet this Tip!

Installing PowerShell Core

As you probably know, Windows PowerShell (the one shipping in Windows) is done, and all efforts go into development of the new cross-platform PowerShell Core. This new PowerShell version is not (yet) shipping out-of-the-box in Windows, so in order to play with it, you need to download it manually.

Fortunately, there is a script that does the heavy-lifting for you. This is how you can download the script source code:

Invoke-RestMethod https://aka.ms/install-powershell.ps1

If you’d like to save the script inside a file, try this:

$Path = "$homedesktopinstallps.ps1"

Invoke-RestMethod https://aka.ms/install-powershell.ps1 | Set-Content -Path $Path -Encoding UTF8
notepad $Path

This downloads the script and opens the script file in Notepad. The script file is located on your desktop, so you can right-click it and execute it with PowerShell to download and install the latest production version of PowerShell Core.


Twitter This Tip! ReTweet this Tip!

Finding Public IP Address

Here is a one-liner that retrieves your current public IP address:

 
PS> Invoke-RestMethod -Uri http://ipinfo.io


ip       : 87.153.224.209
hostname : p5799e0d1.dip0.t-ipconnect.de
city     : Hannover
region   : Lower Saxony
country  : DE
loc      : 52.3705,9.7332
org      : AS3320 Deutsche Telekom AG
postal   : 30159
timezone : Europe/Berlin
readme   : https://ipinfo.io/missingauth
 

Twitter This Tip! ReTweet this Tip!