Wednesday, March 27, 2013

PowerShell Github Projects

I've been working on a few projects in PowerShell. Here is the source code on Github for those interestered.

PowerShell with GUI in Xaml

PowerShell Deployment

Saturday, March 23, 2013

Discover PowerShell - Episode 5

Introduction on using the splatting feature in Windows PowerShell 3.

Disable PowerShell Remoting

Here are a few quick steps to "undo" the default changes performed by Enable-PSRemoting.
PS C:\> Disable-PSRemoting -Force
WARNING: Disabling the session configurations does not undo all the changes made by the Enable-PSRemoting or Enable-PSSessionConfiguration cmdlet. You might have to manua
lly undo the changes by following these steps:
    1. Stop and disable the WinRM service.
    2. Delete the listener that accepts requests on any IP address.
    3. Disable the firewall exceptions for WS-Management communications.
    4. Restore the value of the LocalAccountTokenFilterPolicy to 0, which restricts remote access to members of the Administrators group on the computer.
PS C:\> winrm delete winrm/config/listener?address=*+transport=HTTP
PS C:\> Stop-Service winrm
PS C:\> Set-Service -Name winrm -StartupType Disabled
PS C:\> Set-ItemProperty -Path HKLM:\SOFTWARE\Microsoft\Windows\CurrentVersion\Policies\System -Name LocalAccountTokenFilterPolicy -Value 0 -Type DWord

Discover PowerShell - Episode 4

I've been playing around with PowerShell remoting quite a bit lately and I thought making a tutorial on the basics would help solidify my understanding. Plus, I like teaching so why the heck not?!

Saturday, March 16, 2013

Determine If A Command Exists In PowerShell

Ed Wilson "The Scripting Guy" posted a great article a while back on how to determine if a command exists here. Here is another approach that I came up with that morning.
function Test-Command {
   param($Command)

   $found = $false
   $match = [Regex]::Match($Command, "(?<Verb>[a-z]{3,11})-(?<Noun>[a-z]{3,})", "IgnoreCase")
   if($match.Success) {
       if(Get-Command -Verb $match.Groups["Verb"] -Noun $match.Groups["Noun"]) {
           $found = $true
       }
   }

   $found
}
Here is a breakdown of the regular expression used.
  • The first group in the expression is for the verb, which is 3 to 11 characters long (consult the approved verb list).
  • The second group in the expression is for the noun, which can be 3 or more characters long. I limit the acceptable text to only alphabetical characters and by adding the "IgnoreCase" option we can just use "a-z".
So what would an article be without a quick example.
PS C:\> Test-Command -Command Get-Process
True
PS C:\> Test-Command -Command Get-Proc*
False
Finally, if you would like a shortcut which expects an exact match you can try this:
PS C:\> [bool](Get-Command -Name Get-Process -ea 0)
True

Friday, March 15, 2013

Add Font to PowerShell Console

I saw an article about Adobe's release of a new font called Source Code Pro which was designed in part to help reduce the confusion between certain characters. I thought I would give it a try. After copying the .ttf files to C:\Windows\Fonts, I realized that the font needed to be added in the registry, so here are some steps to get you going.
Change the provider to the registry HKLM: which will get you to HKEY_LOCAL_MACHINE. Navigate to the Console key, then list the properties for TrueTypeFont. Note: I removed some of the extra entries returned by Get-ItemProperty for clarity.
PS C:\> cd HKLM:
PS HKLM:\> cd '.\SOFTWARE\Microsoft\Windows NT\CurrentVersion\Console'
PS HKLM:\SOFTWARE\Microsoft\Windows NT\CurrentVersion\Console> Get-ItemProperty -Path TrueTypeFont


0            : Lucida Console
00           : Consolas
PSPath       : Microsoft.PowerShell.Core\Registry::HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows
               NT\CurrentVersion\Console\TrueTypeFont
PSParentPath : Microsoft.PowerShell.Core\Registry::HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows
               NT\CurrentVersion\Console
PSChildName  : TrueTypeFont
PSDrive      : HKLM
PSProvider   : Microsoft.PowerShell.Core\Registry
Add the new string value. Here I see that 0 and 00 are already used, so we're going to use 000. Then verify the new string exists.
PS HKLM:\SOFTWARE\Microsoft\Windows NT\CurrentVersion\Console> Set-ItemProperty -Path TrueTypeFont -Name 000 -Value 'Source Code Pro'
PS HKLM:\SOFTWARE\Microsoft\Windows NT\CurrentVersion\Console> Get-ItemProperty -Path TrueTypeFont


0            : Lucida Console
00           : Consolas
000          : Source Code Pro
PSPath       : Microsoft.PowerShell.Core\Registry::HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows
               NT\CurrentVersion\Console\TrueTypeFont
PSParentPath : Microsoft.PowerShell.Core\Registry::HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows
               NT\CurrentVersion\Console
PSChildName  : TrueTypeFont
PSDrive      : HKLM
PSProvider   : Microsoft.PowerShell.Core\Registry

Let's try and programmatically set the new font in the console. Create a new PSDrive for the HKEY_USERS hive. Change to the HKU: drive. Change to the SID for the current user. Set the Console property for FaceName to the new font.
PS C:\> New-PSDrive HKU Registry HKEY_USERS

Name           Used (GB)     Free (GB) Provider      Root                                               CurrentLocation
----           ---------     --------- --------      ----                                               ---------------
HKU                                    Registry      HKEY_USERS

PS C:\> cd HKU:
PS HKU:\> cd (New-Object System.Security.Principal.NTAccount($env:USERNAME)).Translate([System.Security.Principal.SecurityIdentifier]).Value
PS HKU:\S-1-5-21-3501008845-2378336731-207489776-1001>
PS HKU:\S-1-5-21-3501008845-2378336731-207489776-1001> Set-ItemProperty -Path Console -Name FaceName -Value 'Source Code Pro'
Now you just need to restart your console and you're good to go!

Saturday, March 9, 2013

Get ValidateSet or Enum Options in PowerShell Command

Edit: I renamed the function because I didn't really like the name.

I've seen a few articles on how to get the valid parameter values for a command, however I thought they were a bit messy. Take for example this:
PS C:\Users\Michael> Set-ExecutionPolicy -ExecutionPolicy WrongValue
Set-ExecutionPolicy : Cannot bind parameter 'ExecutionPolicy'. Cannot convert value "WrongValue" to type
"Microsoft.PowerShell.ExecutionPolicy". Error: "Unable to match the identifier name WrongValue to a valid enumerator
name.  Specify one of the following enumerator names and try again: Unrestricted, RemoteSigned, AllSigned, Restricted,
Default, Bypass, Undefined"
At line:1 char:38
+ Set-ExecutionPolicy -ExecutionPolicy WrongValue
+                                      ~~~~~~~~~~
    + CategoryInfo          : InvalidArgument: (:) [Set-ExecutionPolicy], ParameterBindingException
    + FullyQualifiedErrorId : CannotConvertArgumentNoMessage,Microsoft.PowerShell.Commands.SetExecutionPolicyCommand

As you can see, you have to sift through the error message to get the valid values. On top of that, you can't do anything with the data because it's trapped in a long string of text. This morning I came up with this function to solve that problem for me.
function Get-ParameterOption {
    param(
        $Command,
        $Parameter
    )

    $parameters = Get-Command -Name $Command | Select-Object -ExpandProperty Parameters
    
    $type = $parameters[$Parameter].ParameterType
    if($type.IsEnum) {
        [System.Enum]::GetNames($type)
    } else {
        $parameters[$Parameter].Attributes.ValidValues
    }
}

Here are some examples of using it. Please note that there really isn't any error checking, that will be in the next version :) This example is for Set-ExecutionPolicy:
PS C:\Users\Michael> Get-ParameterOption -Command Set-ExecutionPolicy -Parameter ExecutionPolicy
Unrestricted
RemoteSigned
AllSigned
Restricted
Default
Bypass
Undefined
This example is for a custom function which uses the ValidateSet attribute.
function Do-Something {
    param(
        [ValidateSet("Low","Medium","High")]
        [string]$Option
    )

    "Something happened"
}

PS C:\Users\Michael> Get-ParameterOption -CommandName Do-Something -Parameter Option
Low
Medium
High
PS C:\> Get-ParameterOption -Command Get-Command -Parameter ErrorAction
SilentlyContinue
Stop
Continue
Inquire
Ignore
After I did a little more research, I guess Jeffrey Snover beat me to it.
Programmatic way to get valid string values for a parameter