Archives for the Month of June, 2013

What is OutputType?

If you've seen the OutputType attribute when writing a cmdlet or advanced function, you might wonder what we use it for.

The goal of the OutputType attribute is to provide a mechanism for tools to know what your cmdlets may output without running them. If they know that without running it, they can provide useful services – such as tab completion, data flow analysis, etc.

For example:

Get-Process | Where-Object { $_.<TAB>

When you push TAB, we can look at the pipeline that you’ve just typed, do static analysis of the cmdlet that Where-Object is filtering, and then only display properties from the OutputType (if that cmdlets specifies one).

When writing a cmdlet or advanced funciton, you can type whatever you want as the output type, but you’ll mislead tools if it doesn’t represent a real type that can be reasoned against. The reason that we support the string syntax (in addition to the regular type syntax) is so that the type doesn’t need to be loaded in order for the script to run.

Removing Insecure Wireless Connections with PowerShell

Troy Hunt recently posted a great discussion about the dangers of letting your devices automatically connect to insecure wireless networks – especially if those have a common name like 'Starbucks' or 'Apple Demo'.

All devices let you "forget" a network when you are in range, and Windows 7 (and before) even had an interface that let you delete networks when they were out of range.

This dialog was removed in Windows 8, although the 'netsh' command still lets you accomplish it from the command line.

To fill this gap, a bunch of tools have sprung up, and Scott Hanselman just threw his hat into the ring, too. He wrote a custom C# app ("WiFi.exe"), even mentioning "I could have used PowerShell or something…".

If you wanted to go the PowerShell route, what would that look like? And not just deleting specified networks, but automatically deleting all insecure ones (Automatic, no password).

Quite simple, in fact.

After a few helper functions, it's just "Get-UnsecureWlanProfile | Remove-WlanProfile".

001
002
003
004
005
006
007
008
009
010
011
012
013
014
015
016
017
018
019
020
021
022
023
024
025
026
027
028
029
030
031
032
033
034
035
036
037
038
function Get-WlanProfile
{
    $conn = [Ordered] @{}
    netsh wlan show all | % {
        if($_ -match "^[\s]+(Name|Authentication|Connection Mode)\s+:")
        {
            if($_ -match "Name")
            {
                if($conn.Name -and $conn.Authentication -and $conn."Connection Mode")
                {
                    [PSCustomObject] $conn
                }
                $conn = [Ordered] @{}
            }
           
            $label,$value = $_ -split ':'
            $conn[$label.Trim()] = $value.Trim()
        }
    }
}

function Get-UnsecureWlanProfile
{
    Get-WlanProfile | ? {
        ($_.Authentication -eq 'Open') -and
        ($_."Connection mode" -match "automatically")
    }
}

function Remove-WlanProfile
{
    param(
        [Parameter(ValueFromPipelineByPropertyName)]
        $Name
    )

    netsh wlan delete profile name="$Name"
}

If that's too verbose for you, here is an alternative version as a one-liner:

netsh wlan export profile | ? { $_ } | % { $f = $_ -replace '.*"(.\\.*.xml)".*','$1'; $w = [xml] (gc $f  -raw); if(($w.WLANProfile.MSM.security.authEncryption.authentication -eq 'Open') -and ($w.WLANProfile.connectionMode = 'Automatic')) { netsh wlan delete profile name="$($w.WLANProfile.Name)" }; ri $f }