Monthly Archives: November 2016

Defaulting to PowerShell instead of CMD

Beginning in Windows 8.1, you could set the Windows PowerUser menu (right-click on the Start button, or Win-X key) to show Windows PowerShell and Windows PowerShell (Admin) on the menu instead of Command Prompt and Command Prompt (Admin). But every single new machine you log on to, you had to change that. A nuisance, at least. So, I created a Group Policy Preference to set the registry key for this, and linked this to the Default Domain Policy.

Apparently, Microsoft is finally catching up, and this is going to be the default on Windows 10 beginning with the build that's coming down today. About time!

For those of you who are not on the Fast Ring of Windows Insider builds, the registry key you need to set is:

HKCU:\Software\Microsoft\Windows\CurrentVersion\Explorer\Advanced\DontUsePowerShellOnWinX=0

To set that with Windows PowerShell, use:

Set-ItemProperty HKCU:\Software\Microsoft\Windows\CurrentVersion\Explorer\Advanced `
                -Name DontUsePowerShellOnWinX `
                -Value 0 `
                -Type DWord

You can also use Group Policy Preferences to set that as part of a Group Policy Object (GPO).

    1. Open the Group Policy Management Console (gpmc.msc)
    2. Right-click the GPO you want to modify (I chose the Default Domain Policy for my domain)
    3. Select Edit from the right-click menu to open the Group Policy Editor
    4. Expand the User Configuration container, then Preferences and select Registry in the left pane.
    5. Right-click in the Registry details pane and select Registry Item from the New menu:
Adding a new registry item to Group Policy Preferences

Add a new registry item to Group Policy Preferences

6. In the New Registry Properties dialog, select Update for the Action, HKEY_CURRENT_USER for the Hive, and a Key Path of  \Software\Microsoft\Windows\CurrentVersion\Explorer\Advanced.

Set PowerShell as the WinX default

Set PowerShell as the WinX default

7. The Value Name is DontUsePowerShellOnWinX, with a Value Type of REG_DWORD and a Value Data of 0, as shown below.

8. Click OK, and then close GPEdit. The Group Policy will be applied to following the next reboot and logon of each user to whom the GPO applies.

For those of you who insist that they really want CMD instead of PowerShell, you can simply set the value of that registry item to one (1) instead of zero (0). Or let users manually control it. But as I've been saying for years: "Death to CMD". :)

 

Using a list as a default parameter value

I got an interesting question in a comment today on my old post on Getting the Free Disk Space of Remote Computers. While I answered the comment in the original post, it brought up something that's not well understood, so I thought I'd take a moment to give a fuller answer here, where it will be more discoverable.

 

The reader complained that when he ran the script without parameters, he was getting an error. When I read the error, it was clear that he had modified the script to set a default value for the ComputerName parameter that was a list of computers, rather than a single computer. A reasonable change, since the script is set to handle a list or array of strings with [string[]]. And if you use the parameter with a list of -ComputerName 'server1','server2','server3', etc., from the command line, it handles that list as you would expect. But if you try to set a default value for the ComputerName parameter with that same list:

[CmdletBinding()]
Param ([Parameter(Mandatory=$False,Position=0)]
       [String[]]$ComputerName = 'server1','server2','server3')

You'll get an error:

Missing expression after ','

So, does this mean you can't set a default value that is a list? Of course not! But it does mean you need to let PowerShell know explicitly what you're doing. When you pass in an adhoc list like that from the command line, it just works because PowerShell does a fair amount of magic for things it sees on the command line. But in a script, we need to be more explicit. So, instead, we need to declare our list as... A List! We do that with:

[CmdletBinding()]
Param ([Parameter(Mandatory=$False,Position=0)]
       [String[]]$ComputerName = @('server1','server2','server3'))

Now, our script works as we'd expect. It accepts my default list of server1, server2, server3, but allows me to override that list with my own list at the command line. (And remember, a list can be a list of length one, having only a single member. )