Archive

Posts Tagged ‘Registry’

Accessing PowerShell Properties and Variables with Periods (and other special characters) in their Name

September 5th, 2013 No comments

TL;DR

If your PowerShell variable name contains special characters, wrap it in curly braces to get/set its value.  If your PowerShell property name contains special characters, wrap it in double quotes:

# Variable name with special characters
$VariableName.That.Contains.Periods			# This will NOT work.
${VariableName.That.Contains.Periods}		# This will work.

$env:ProgramFiles(x86)			# This will NOT work, because parentheses are special characters.
${env:ProgramFiles(x86)}		# This will work.

# Property name with special characters
$SomeObject.APropertyName.That.ContainsPeriods		# This will NOT work.
$SomeObject.{APropertyName.That.ContainsPeriods}	# This will work.
$SomeObject.'APropertyName.That.ContainsPeriods'	# This will also work.
$SomeObject."APropertyName.That.ContainsPeriods"	# This will work too.

# Property name with special characters stored in a variable
$APropertyNameWithSpecialCharacters = 'APropertyName.That.ContainsPeriods'
$SomeObject.$APropertyNameWithSpecialCharacters		# This will NOT work.
$SomeObject.{$APropertyNameWithSpecialCharacters}	# This will NOT work.
$SomeObject.($APropertynameWithSpecialCharacters)	# This will work.
$SomeObject."$APropertynameWithSpecialCharacters"	# This will also work.
$SomeObject.'$APropertynameWithSpecialCharacters'	# This will NOT work.

 

More Information

I was recently working on a powershell script to get the values of some entries in the registry.  This is simple enough:

Get-ItemProperty -Path 'HKCU:\Software\Microsoft\VisualStudio\11.0_Config\TeamFoundation\SourceControl\Checkin Policies' -Name 'TF.iQmetrix.CheckinPolicies'

If we run this command, this is what we get back:

TF.iQmetrix.CheckinPolicies : C:\Users\Dan Schroeder\AppData\Local\Microsoft\VisualStudio\11.0\Extensions\mwlu1noz.4t5\TF.iQmetrix.CheckinPolicies.dll
PSPath                      : Microsoft.PowerShell.Core\Registry::HKEY_CURRENT_USER\Software\Microsoft\VisualStudio\11.0_Config\TeamFoundation\SourceControl\Checkin Policies
PSParentPath                : Microsoft.PowerShell.Core\Registry::HKEY_CURRENT_USER\Software\Microsoft\VisualStudio\11.0_Config\TeamFoundation\SourceControl
PSChildName                 : Checkin Policies
PSDrive                     : HKCU
PSProvider                  : Microsoft.PowerShell.Core\Registry

So the actual value I’m after is stored in the “TF.iQmetrix.CheckinPolicies” property of the object returned by Get-ItemProperty; notice that this property name has periods in it.  So let’s store this object in a variable to make it easier to access it’s properties, and do a quick Get-Member on it just to show some more details:

$RegistryEntry = Get-ItemProperty -Path 'HKCU:\Software\Microsoft\VisualStudio\11.0_Config\TeamFoundation\SourceControl\Checkin Policies' -Name 'TF.iQmetrix.CheckinPolicies'
$RegistryEntry | Get-Member

And this is what Get-Member shows us:

   TypeName: System.Management.Automation.PSCustomObject

Name                        MemberType   Definition                                                                                                                                                          
----                        ----------   ----------                                                                                                                                                          
Equals                      Method       bool Equals(System.Object obj)                                                                                                                                      
GetHashCode                 Method       int GetHashCode()                                                                                                                                                   
GetType                     Method       type GetType()                                                                                                                                                      
ToString                    Method       string ToString()                                                                                                                                                   
PSChildName                 NoteProperty System.String PSChildName=Checkin Policies                                                                                                                          
PSDrive                     NoteProperty System.Management.Automation.PSDriveInfo PSDrive=HKCU                                                                                                               
PSParentPath                NoteProperty System.String PSParentPath=Microsoft.PowerShell.Core\Registry::HKEY_CURRENT_USER\Software\Microsoft\VisualStudio\11.0_Config\TeamFoundation\SourceControl           
PSPath                      NoteProperty System.String PSPath=Microsoft.PowerShell.Core\Registry::HKEY_CURRENT_USER\Software\Microsoft\VisualStudio\11.0_Config\TeamFoundation\SourceControl\Checkin Policies
PSProvider                  NoteProperty System.Management.Automation.ProviderInfo PSProvider=Microsoft.PowerShell.Core\Registry                                                                             
TF.iQmetrix.CheckinPolicies NoteProperty System.String TF.iQmetrix.CheckinPolicies=C:\Users\Dan Schroeder\AppData\Local\Microsoft\VisualStudio\11.0\Extensions\mwlu1noz.4t5\TF.iQmetrix.CheckinPolicies.dll 

 

So in PowerShell ISE I type “$RegistryEntry.” and intellisense pops up showing me that TF.iQmetrix.CheckinPolicies is indeed a property on this object that I can access.

PowerShell ISE Intellisense

So I try and display the value of that property to the console using:

$RegistryEntry = Get-ItemProperty -Path 'HKCU:\Software\Microsoft\VisualStudio\11.0_Config\TeamFoundation\SourceControl\Checkin Policies' -Name 'TF.iQmetrix.CheckinPolicies'
$RegistryEntry.TF.iQmetrix.CheckinPolicies

But nothing is displayed Sad smile

While PowerShell ISE does color-code the line “$RegistryEntry.TF.iQmetrix.CheckinPolicies” to have the object color different than the property color, if you just look at it in plain text, something clearly looks off about it.  How does PowerShell know that the property name is “TF.iQmetrix.CheckinPolicies”, and not that “TF” is a property with an “iQmetrix” property on it, with a “CheckinPolicies” property on that.  Well, it doesn’t.

I did some Googling and looked on StackOverflow, but couldn’t a solution to this problem.  I found slightly related posts involving environmental variables with periods in their name, but that solution did not work in this case.  So after some random trial-and-error I stumbled onto the solution.  You have to wrap the property name in curly braces:

$RegistryEntry.TF.iQmetrix.CheckinPolicies		# This is WRONG. Nothing will be returned.
$RegistryEntry.{TF.iQmetrix.CheckinPolicies}	# This is RIGHT. The property's value will returned.

 

I later refactored my script to store the “TF.iQmetrix.CheckinPolicies” name in a variable and found that I couldn’t use the curly braces anymore.  After more trial-and-error I discovered that using parentheses instead works:

$EntryName = 'TF.iQmetrix.CheckinPolicies'

$RegistryEntry.$EntryName		# This is WRONG. Nothing will be returned.
$RegistryEntry.{$EntryName}		# This is WRONG. Nothing will be returned.
$RegistryEntry.($EntryName)		# This is RIGHT. The property's value will be returned.
$RegistryEntry."$EntryName"		# This is RIGHT too. The property's value will be returned.

 

So there you have it.  If for some reason you have a variable or property name that contains periods, wrap it in curly braces, or parenthesis if you are storing it in a variable.

Hopefully this makes it’s way to the top of the Google search results so you don’t waste as much time on it as I did.

Happy coding!

Fix Problem Where Windows PowerShell Cannot Run Script Whose Path Contains Spaces

May 28th, 2013 4 comments

Most people will likely find the “Run script path with spaces from File Explorer” (to be able to double click a PS script whose path contains spaces to run it) section below the most helpful.  Most of the other content in this post can be found elsewhere, but I provide it for context and completeness.

 

Make running (instead of editing) the default PowerShell script action

The default Windows action when you double click on a PowerShell script is to open it in an editor, rather than to actually run the script.  If this bugs you, it’s easy enough to fix.  Just right-click on the script, go to “Open with” –> “Choose default program…”, and then select Windows PowerShell, making sure the “Use this app for all .ps1 files” option is checked (this might be called “Always use the selected program to open this kind of file” or something else depending on which version of Windows you are using).

ChooseDefaultPowerShellApplication     MakeWindowsPowerShellDefaultApplication

If you don’t mind opening in an editor as the default action, then to run the script you can just right-click on the script and choose “Open with” –> “Windows PowerShell”.  This is probably how 90% of people run their PowerShell scripts; power uses might run their scripts directly from the PowerShell command prompt.

 

Error message when trying to run a script whose path contains spaces

So the problem that the 90% of people are likely to encounter is that as soon as the script path has a space in it (either in the filename itself or in the directory path the file resides in), they will see the powershell console flash some red text at them for about 1/10th of a second before it closes, and they will be wondering why the script did not run; or worse, they won’t know that it didn’t run (see the “Keep PowerShell Console Open” section below).  If they are lucky enough to press Print Screen at the right moment, or decide to open up a PowerShell console and run from there, they might see an error message similar to this:

Powershell Invalid Path Error Message

“The term ‘C:\My’ is not recognized as the name of a cmdlet, function, script file, or operable program. Check the spelling of the name, or if a path was included, verify that the path is correct and try again.”

So the path to the script I was trying to run is "C:\My Folder\My PowerShell Script.ps1", but from the error you can see that it cut the path off at the first space.

 

Run script path with spaces from PowerShell console

So the typical work around for this is to open a PowerShell console and run the script by enclosing the path in double quotes.

Windows 8 Pro Tip: You can open the PowerShell console at your current directory in File Explorer by choosing File –> Open Windows PowerShell.

Open Powershell From File Explorer

If you simply try to run the script by enclosing the path to the script in double quotes you will just see the path spit back at you in the console, instead of actually running the script.

Try to run script with spaces the wrong way

The trick is that you have to put “& “ before the script path to actually run the script.  Also, if you are trying to run a script from the current directory without using the full path, you will need to put “.\” before the relative script filename.

Run PowerShell script the right way

 

Run script path with spaces from File Explorer

So when we are in the PowerShell console we can manually type the path enclosed in double quotes, but what do we do when simply trying to run the file from File Explorer (i.e. Windows Explorer in Windows 7 and previous) by double clicking it? 

The answer: Edit the registry to pass the file path to powershell.exe with the path enclosed in quotes.

The problem is that the “HKEY_CLASSES_ROOT\Applications\powershell.exe\shell\open\command” registry key value looks like this:

"C:\Windows\System32\WindowsPowerShell\v1.0\powershell.exe" "%1"

but we want it to look like this:

"C:\Windows\System32\WindowsPowerShell\v1.0\powershell.exe" "& \"%1\""

 

So if you want to go manually edit that key by hand you can, or you can simply download the registry script below and then double click the .reg file to have it update the registry key value for you (choose Yes when asked if you want to continue).

Windows Registry Editor Version 5.00

[HKEY_CLASSES_ROOT\Applications\powershell.exe\shell\open\command]
@="\"C:\\Windows\\System32\\WindowsPowerShell\\v1.0\\powershell.exe\" \"& \\\"%1\\\"\""

IMHO this seems like a bug with the PowerShell installer (and Windows since PowerShell is built into Windows 7 and up), so please go up-vote the bug I submitted to get this fixed.

So now you can run your PowerShell scripts from File Explorer regardless of whether their path contains spaces or not Smile.  For those interested, this is the post that got me thinking about using the registry to fix this problem.

 

Bonus: Keep PowerShell console open when script is ran from File Explorer

Update – This Bonus section now has its own updated dedicated post here that you should use instead.

When running a script by double-clicking it, if the script completes very quickly the user will see the PowerShell console appear very briefly and then disappear.  If the script gives output that the user wants to see, or if it throws an error, the user won’t have time to read the text.  The typical work around is to open the PowerShell console and manually run the script.  The other option is to adjust our new registry key value a bit.

So to keep the PowerShell console window open after the script completes, we just need to change our new key value to use the –NoExit switch:

"C:\Windows\System32\WindowsPowerShell\v1.0\powershell.exe" –NoExit "& \"%1\""

And here is the .reg script with the –NoExit switch included:

Windows Registry Editor Version 5.00

[HKEY_CLASSES_ROOT\Applications\powershell.exe\shell\open\command]
@="\"C:\\Windows\\System32\\WindowsPowerShell\\v1.0\\powershell.exe\" -NoExit \"& \\\"%1\\\"\""

I hope you find this information as useful as I did.  Happy coding!