Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to read PowerShell .PSD1 files safely

Tags:

The PowerShell module manifest file format (.psd1) is essentially a Hashtable literal with certain keys expected. This is ideal for a configuration file for a PowerShell script. What I ultimately want to do is read a .psd1 file that contains a set of keys specific to the script.

For example (MyScriptConfig.psd1):

@{     FTPHost = "ftp.blah.com"     FTPUserName = "blah"     FTPPassword = "blah" } 

There's no reason I can't use XML, INI, JSON or whatever for this information, but I'd rather it use the same basic data format as PowerShell's module manifests.

Obviously the easiest thing would be to read the text and pass it to Invoke-Expression which would return a Hashtable, but then it would invoke anything that's in the file, which is error prone and potentially unsafe.

I thought I recalled a cmdlet for reading this data using a "safe" subset of PowerShell cmdlets, but I was thinking of ConvertFrom-StringData and DATA sections, neither of which let me read an arbitrary file containing a Hashtable literal.

Is there something built into PowerShell that lets me do this? If there's nothing built in, then I would probably go the route of JSON or Key=Value with ConvertFrom-StringData.

like image 951
Josh Avatar asked Aug 20 '14 15:08

Josh


2 Answers

Powershell version 5 added the Cmdlet Import-PowershellDataFile for safely parsing PSD1 files.

Prior to version 5, there were at least three solutions:

  1. The Cmdlet Import-LocalizedData. Which, though intended for processing language files, will read any PSD1 formatted file.

    # Create a test PSD1 file @'     @{         a1 = 'a1'         a2 = 2         a3 = @{           b1 = 'b1'         }     } '@ | Set-Content -Path .path\example.psd1  # Read the file Import-LocalizedData -BaseDirectory .\path -FileName example.psd1 -BindingVariable Data  # Use the data $Data.a1 $Data.a3.b1 
  2. It is also possible to process in-line data with a Data Section (in-line sort of defeats the purpose).

    # Safely parse data $Data2 = DATA {     @{         a1 = 'a1'         a2 = 2         a3 = @{           b1 = 'b1'         }     } }  # Use the data $Data2.a1 $Data2.a3.b1 
  3. The third being the PowerShell DSC parameter transformation attribute mentioned by @Jakub Berezanski.

like image 186
Nathan Hartley Avatar answered Oct 16 '22 17:10

Nathan Hartley


PowerShell DSC defines a parameter transformation attribute, used to support passing a path to a .psd1 file as the value of the ConfigurationData parameter when invoking a Configuration. This attribute is public and can be used in a custom function, such as:

function Parse-Psd1 {     [CmdletBinding()]     Param (         [Parameter(Mandatory = $true)]         [Microsoft.PowerShell.DesiredStateConfiguration.ArgumentToConfigurationDataTransformation()]         [hashtable] $data     )     return $data } Parse-Psd1 C:\MyData.psd1 

The attribute implementation calls an internal helper that evaluates the contents of the file in a restricted language context, where only the following cmdlets are permitted:

Import-LocalizedData ConvertFrom-StringData Write-Host Out-Host Join-Path 
like image 39
Jakub Berezanski Avatar answered Oct 16 '22 17:10

Jakub Berezanski