Create cryptographically secure and pseudorandom data with PowerShell

From Svendsen Tech PowerShell Wiki
Jump to: navigation, search

Svendsen Tech's advanced PowerShell function New-RandomData can be used to generate both pseudorandom and cryptographically secure random data. The default is writing one or more ASCII encoded text files with \r\n line endings, but you can also use it to generate passwords, keys, and random numbers to store in a variable, etc., with the -RandomChar and/or -StreamToSTDOUT parameters. I will demonstrate its use.

Should work with PowerShell version 2 and up. The testing has been done with PowerShell version 4.


This image shows that it takes about 2.2 seconds to generate a 1 MiB large pseudorandom file on my (2009 vintage) system.


This image shows that it took almost exactly 24 seconds to generate a 1 MiB cryptographically secure file on my (2009 vintage) system, using the default random character set that has no overhead.


If we fast forward to my new computer from late in 2017, running PowerShell 5.1 on Windows 10, the speed is much better, as seen in this screenshot:



New-RandomData.ps1.txt - right-click and download, rename, remember to unblock. Dot-source (. .\New-RandomData.ps1), and use the New-RandomData cmdlet. - Module version. Exports the function New-RandomData. Download, remember to unblock before extracting (Unblock-File in PSv3 and up), copy the directory containing the module files to a PowerShell module folder. See $Env:PSModulePath. Also published to the PowerShell gallery (see below).

  • 2017-01-21: Uploading a module version, 1.2, which is identical to the existing script, except it's been given the mandatory scaffolding to be a module. I published it to the PowerShell gallery for convenient access (see below). Adding the zip file to the wiki as well.
  • 2016-03-12: Small optimizations. Generating two less random characters per line when writing a file, where \r\n will occupy two bytes, which means retrieving fewer random cryptography numbers, or fewer pseudorandom numbers, plus less appending to the string builder.
    • Speed for a 1 MiB file of pseudorandom data went from about 2.2 to 1.5 seconds on my system. Cryptography difference was not really noticeable.
  • 2016-02-18: Changed the string manipulation to be done with System.Text.StringBuilder. Cut run time down to less than half for the 1 MiB pseudorandom test case - and about 40 % faster with -Cryptography specified for 1 MiB.

Earlier versions: File:New-RandomData.ps1.txt. Earlier module versions:

If you have Windows Management Framework 5 or higher (WMF 5 is available for Windows 7 and up), you can install my RandomData module from the PowerShell gallery, a Microsoft site and online repository for scripts.

To install with WMF 5 and up (to get the latest RandomData module version available), simply run this command (requires an internet connection):

Install-Module -Name RandomData

Or for your user only (no elevation required):

Install-Module -Name RandomData -Scope CurrentUser

Generating a random 100-digit number

We specify a random char array containing 0-9, a size and line length of 100, and off we go. Add -StreamToSTDOUT and assign to a variable. I realize this example is a bit odd in retrospect. See the password generation below as well.

A convenient way to specify for instance “a-z” as a char array for either -RandomChar or -RandomCharExclude is using this syntax: -RandomChar ([char]’a’ .. [char]‘z’)

PS C:\dir> New-RandomData -Size 100 -LineLength 100 -Cryptography `
    -RandomChar ([char[]][string[]](0..9)) -Verbose
VERBOSE: Random char array: 0, 1, 2, 3, 4, 5, 6, 7, 8, 9
VERBOSE: Random char array size: 10
VERBOSE: Duplicating array of length 10 completely 25 times, to fit a byte-sized array as closely as possible.
VERBOSE: Random char array size after duplication: 250.
VERBOSE: Probability of generating an unusable cryptography number (overhead): 2.34 %.
VERBOSE: Wrote 'C:\dir\random_file-1.txt'. 02/16/2016 23:45:51.
VERBOSE: Had to get 101 cryptography numbers.

PS C:\dir> gc .\random_file-1.txt

PS C:\dir> gc .\random_file-1.txt | %{ $_.Length } # \r\n take up 2 bytes

PS C:\dir> ls .\random_file-1.txt | ft -AutoSize length, name

Length Name             
------ ----             
   100 random_file-1.txt

Generating a random password

There are simpler solutions for this, but New-RandomData can absolutely be used to generate random passwords (or keys), even cryptographically secure if you specify the -Cryptography parameter.

Use the -StreamToSTDOUT parameter and set the size and line length to the same, desired password length.

PS C:\> $RandomPassword = New-RandomData -Size 12 -LineLength 12 -StreamToSTDOUT

PS C:\> $RandomPassword

You can also specify which characters to use for the password via the -RandomChar parameter. A convenient way to specify for instance "a-z" and "0-9" as a char array for either -RandomChar or -RandomCharExclude is using the syntax "-RandomChar ([char]'a' .. [char]'z' + [char]'0' .. [char]'9')".

Cryptographically secure random data

The parameter -Cryptography turns on the feature that uses a cryptographically secure random number generator to index into the equally weighted, possibly repeated, as-close-as-possible-to-byte-sized random char array. This uses the .NET System.Security.Cryptography random number generator to generate random numbers to index into the array.

If you do not use a random characters array by which 256 is evenly divisible, there will be some overhead. The -Verbose parameter will (among other things) tell you how large the overhead in potentially wastefully generated unusable numbers is estimated to be, as a percentage.

The default set of random characters is a-z, A-Z, 0-9, "-", and "_". This is 64 characters which means it can be repeated four times to perfectly fit a byte-sized array, causing no overhead.

PS C:\> New-RandomData -Size 1024 -LineLength 64 -StreamToSTDOUT `
    -Cryptography -Verbose
VERBOSE: Random char array: a, b, c, d, e, f, g, h, i, j, k, l, m, n, o, p, q, r, s, t, u, v, 
w, x, y, z, A, B, C, D, E, F, G, H, I, J, K, L, M, N, O, P, Q, R, S, T, U, V, W, X, Y, Z, 0, 1
, 2, 3, 4, 5, 6, 7, 8, 9, -, _
VERBOSE: Random char array size: 64
VERBOSE: Duplicating array of length 64 completely 4 times, to fit a byte-sized array as close
ly as possible.
VERBOSE: Random char array size after duplication: 256.
VERBOSE: Probability of generating an unusable cryptography number (overhead): 0.00 %.
VERBOSE: Had to get 1024 cryptography numbers.

PS C:\>  

Generating 1000 random data files

The -Count parameter is simple enough and specifies the number of files to create, with zero-padded numbers added. If you provide the -RandomFileNameGUID switch parameter, a GUID will be appended to the file base name, which by default is “random_file-“. The extension (default .txt) is thrown at the end.

It took about 17-18 seconds to generate 1000 files of size 8192 bytes (8 KiB of data). Still on my desktop computer from 2009.

PS C:\temp\dir> Get-ChildItem

PS C:\temp\dir> . C:\Dropbox\PowerShell\New-RandomFile\New-RandomData.ps1

PS C:\temp\dir> Measure-Command { New-RandomData -Path (Get-Location) -Count 1000 `
  -Size 8192 -LineLength 256 } | % { 'Total seconds: ' + $_.TotalSeconds } 
Total seconds: 17.8322021

PS C:\temp\dir> (Get-ChildItem).count 

PS C:\temp\dir> ls | select -first 3

    Directory: C:\temp\dir

Mode                LastWriteTime     Length Name
----                -------------     ------ ----
-a---        2016-03-26     01:52       8192 random_file-0001.txt
-a---        2016-03-26     01:52       8192 random_file-0002.txt
-a---        2016-03-26     01:52       8192 random_file-0003.txt

PS C:\temp\dir> ls | select -last 3

    Directory: C:\temp\dir

Mode                LastWriteTime     Length Name
----                -------------     ------ ----
-a---        2016-03-26     01:53       8192 random_file-0998.txt
-a---        2016-03-26     01:53       8192 random_file-0999.txt
-a---        2016-03-26     01:53       8192 random_file-1000.txt

PS C:\temp\dir> 

If we look at a random file and its random data (the last -replace just splits it into 64 characters per line), we can see that the last line, the end of the 256 characters long line, has 2 bytes less than the specified line length of 256 to make room for a carriage return and a newline in the file. With -StreamToSTDOUT, this does not happen.

PS C:\temp\dir> gc .\random_file-0888.txt | select -first 1 | 
    %{ $_ -replace '(.{64}(?!$))', "`${1}`n" }


These are the parameters for New-RandomData.

Path Directory to store random file in. Default is current working directory ($Pwd.Path). Use "(Get-Location)" for current directory, not ".", because that defaults to the profile directory inside the cmdlet.
BaseName If generating one file, it is the file name plus a 1 plus the extension. If generating more than one file, it is the base name for the file plus a possibly zero-padded count number. If you specify -RandomFileNameGUID, a GUID will be appended to this base name instead of the count number, making the file name also pseudorandom. The default is "random_file-".
Extension The extension used for the generated files.
Count Number of files to generate. The default is 1.
Size File size in bytes. Default 1024 B. If you specify a line length which the size is not evenly divisible by, the size can be off by +/- 1 byte.
LineLength Number of bytes per line, including \r\n if writing a file. If you specify a line length which the specified size is not evenly divisible by, the size can be off by +/- 1 byte. LineLength cannot be greater than the specified size.
NoClobber Do not overwrite existing files with the same name.
RandomChar Random char array of chars to use for generating the pseudorandom or cryptographically secure random data. Default: [A-Za-z0-9_-]. 64 characters. Fits perfectly in a byte-sized array when repeated four times, making it as efficient as possible when generating cryptographically secure data, while preserving equal weighting of characters.
RandomCharExclude Characters to exclude from the default set of characters (or the supplied set).
NoRandomData Use fsutil and generate a file filled with zero bytes (`0 or \0) extremely fast. NB! No random data with this option.
RandomFileNameGUID Append a GUID to the file base name, making the file name (also) pseudorandom.
Cryptography Use a cryptographically secure random number generator to pick random data from the char array rather than a pseudorandom number generator.
StreamToSTDOUT Do not write any files, but stream random data to STDOUT.