Monitor current RDG connections

To obtain the same output as the remote desktop gateway snap-in (tsgateway.msc), aka the RD Gateway Manager, you can use the following function that accepts server names and credentials as input:

Function Get-RDGConnections            
{            
    [CmdletBinding(DefaultParameterSetName='Computer', SupportsTransactions=$false)]            
    param(            
       [Parameter(ParameterSetName='Computer', ValueFromPipeline=$true, Mandatory=$false, Position=0)]            
        [system.string[]]${ComputerName},            
            
       [Parameter(ParameterSetName='Computer', ValueFromPipeline=$false, Mandatory=$false, Position=1)]            
        [System.Management.Automation.PSCredential]$Credential = $null            
    )            
            
    begin            
    {            
            # Check if we've got the value from the pipeline            
            $direct = $PSBoundParameters.ContainsKey('ComputerName')            
            
            # Build a hashtable for splatting            
            $otherparams = @{}            
            if ($credential)            
            {            
                $otherparams += @{Credential = $Credential}            
            }            
            
    }            
    process            
    {            
        $resultsar = @()            
        foreach ($computer in $ComputerName)            
        {            
            $allRDGconnections = @()            
            # Write-Verbose -Message "Dealing with $computer" -Verbose:$true            
            try            
            {            
                # http://social.technet.microsoft.com/Forums/en-US/winserverpowershell/thread/85e0c2bf-abca-4cf9-9355-cb066344a7d5/            
                $allRDGconnections = @(Get-WmiObject -class "Win32_TSGatewayConnection" -namespace "root\cimv2\TerminalServices" -ComputerName $computer -Authentication 6 -ErrorAction Stop @otherparams)            
            }             
            catch            
            {            
                # WMI was unable to retrieve the information            
                switch ($_)            
                {            
                    # sort out most common errors and return qualified information            
                    {          $_.Exception.ErrorCode -eq 0x800706ba} { $reason = 'Unavailable (offline, firewall)' }            
                    {          $_.CategoryInfo.Reason -eq 'UnauthorizedAccessException' } { $reason = 'Access denied' }            
                    # {          $_.Exception.ErrorCode -eq 0x80070005} { $reason = 'Access denied' }            
                    # return all other non-common errors            
                    default { $reason = $_.Exception.Message }            
                } # end of switch            
                if ($direct) {Write-Host -ForegroundColor Red -Object ("Failed to connected to $computer because $reason")  }            
            } # end of catch            
            if ($allRDGconnections.Count -ne 0)            
            {            
                foreach ($item in $allRDGconnections)            
                {            
                    # Write-Verbose -Message "Adding $($item.ConnectedResource)" -Verbose:$true            
                    $resultsar += New-Object -TypeName PSObject -Property @{            
                        ViaRDGServer = $computer            
                        ConnectionID  = $item.ConnectionKey            
                        UserName = $item.FullUserName            
                        TargetComputer = $item.ConnectedResource            
                        UserID = $item.UserName            
                        ClientIPAddress = $item.ClientAddress               
                        ConnectionDuration = [System.Management.ManagementDateTimeConverter]::ToTimeSpan(($item.ConnectionDuration))            
                        ConnectedOn = $item.ConvertToDateTime($item.ConnectedTime)            
                        IdleTime = [System.Management.ManagementDateTimeConverter]::ToTimeSpan(($item.IdleTime))            
                        TargetPort = $item.ConnectedPort            
                        KilobytesReceived= $item.NumberOfKilobytesReceived            
                        KilobytesSent = $item.NumberOfKilobytesSent            
                     }            
                }            
            } else {            
                if ($direct) {Write-Host -ForegroundColor Yellow -Object ("No body connected on $computer")}            
            }            
        } # end of foreach $computer            
        # Output results            
        if ($resultsar -ne $null)            
        {            
            return $resultsar            
        }            
    }            
    end {}            
} # end of function

IOW, you can do now for example:

Get-RDGConnections -ComputerName "RDGServer1","IP.of.RDG.server2" | Format-Table -AutoSize -Wrap -Property *

Or

"RDGServer1","IP.of.RDG.server2" | Get-RDGConnections -Credential (Get-Credential) | Format-Table -AutoSize -Wrap -Property *

Audit RDG Connections

Don’t get confused, RDG in the acronym for “Remote Desktop Gateway“, formerly known as TSG (Terminal Service Gateway) that is the endpoint of encapsulated remote desktop’s connections through a HTTPS tunnel. To get the history of remote desktop accesses via the gateway, you can do:

# Extract info from logs            
$RDGevents = Get-WinEvent -FilterHashtable @{Logname = "Microsoft-Windows-TerminalServices-Gateway/Operational" ; ID = "303","302","202","307"} -ErrorAction SilentlyContinue            
            
$eventsar = @()            
foreach ($event in $RDGevents)            
{            
    $eventtype = $type = $null            
    # http://technet.microsoft.com/en-us/library/ee891388%28WS.10%29.aspx            
    switch ($event.ID)            
    {            
     303 { $eventtype = "disconnect" }            
     307 { $eventtype = "disconnect at timeout" }            
     202 { $eventtype = "disconnected by admin" }            
     302 { $eventtype = "connect" }            
     } # end of switch                
            
            
    $eventsar += New-Object -TypeName PSObject -Property @{            
                    RDGServerName = $env:computername            
                    UserName = $event.Properties[0].Value            
                    IpAddress = [net.ipaddress]$event.Properties[1].Value            
                    Resource = $Event.Properties[3].Value            
                    TimeCreated = $event.TimeCreated            
                    Result = $eventtype            
                }            
}                        
            
# Display results            
$eventsar | Sort-Object -Descending:$false -Property TimeCreated | Format-Table -AutoSize -Wrap

Audit RDP connections

As you may know, it’s quite urgent to apply MS12-020 and/or at least to apply mitigations.

You may be interested in tracking RDP logons as well. As far as I know there are actually 2 ways to achieve this depending on your audit policy settings.

By default, you can do:

# Extract info from logs            
$allRDPevents = Get-WinEvent -FilterHashtable @{Logname = "Microsoft-Windows-TerminalServices-RemoteConnectionManager/Operational" ; ID = 1149,1150,1148} -ErrorAction SilentlyContinue            
            
$RDPevents = @()              
foreach ($event in $allRDPevents)            
{            
    $result = $type = $null            
    # http://technet.microsoft.com/en-us/library/ee891195%28v=ws.10%29.aspx            
    switch ($event.ID)            
    {            
        1148 { $result = "failed"    }            
        1149 { $result = "succeeded" }            
        1150 { $result =  "merged"   }            
    }            
    $RDPevents += New-Object -TypeName PSObject -Property @{            
                    ComputerName = $env:computername            
                    User = $event.Properties[0].Value            
                    Domain = $event.Properties[1].Value            
                    SourceNetworkAddress = [net.ipaddress]$Event.Properties[2].Value            
                    TimeCreated = $event.TimeCreated            
                    Result = $result            
                }            
}            
            
# Display results            
$RDPevents | Sort-Object -Descending:$true -Property TimeCreated | Format-Table -AutoSize -Wrap            

If you enable ‘Audit Other Logon/Logoff events’ in your auditing policy settings you can then get additional info like this:

# More filtering can be added to this here-string XML             
$xml=@"

  
    
	*[System
	   [
	    (Level=1  or Level=2 or Level=3 or Level=4 or Level=0 or Level=5)
	    and ( EventID=4778 or EventID=4779 )
	   ]
	]
   
  

"@            
            
$events = Get-WinEvent -FilterXml $xml -ErrorAction SilentlyContinue            
            
$RDPevents = @()              
foreach ($event in $events)            
{            
    # Define a pattern that matches an IP address            
    $pattern = '^(?:(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.){3}(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)$'            
    # Reset variable            
    $IP = $type = $null            
            
    switch($Event.Properties[5].Value)            
    {            
        { $_ -ieq "LOCAL"    } { $IP = "Local" }            
        { $_ -match $pattern } { $IP = [system.net.ipaddress]$Event.Properties[5].Value }            
        default                { $IP = $Event.Properties[5].Value }            
    }            
            
    switch ($event.ID)            
    {            
        4778 { $type = "Session Reconnected"  }            
        4779 { $type = "Session Disconnected" }            
    }            
            
    $RDPevents += New-Object -TypeName PSObject -Property @{            
                    ComputerName = $env:computername            
                    User = $event.Properties[0].Value            
                    Domain = $event.Properties[1].Value            
                    SourceNetworkAddress = $IP            
                    SourceComputerName = $event.Properties[4].Value            
                    RDPSessionName = $event.Properties[3].Value            
                    TimeCreated = $event.TimeCreated            
                    Result = "Success"            
                    Type = $type            
                }            
}            
            
$RDPevents | Sort-Object -Descending:$true -Property TimeCreated | Format-Table -AutoSize -Wrap

Beware of character [int]160

While working on the OperatingSystem attribute of computer objects in Active Directory, we noticed that some fields have special characters like “™” and “®”.
A few months later, when we exported these fields to a CSV ASCII file, we noticed that there were additional characters.
When we looked in the console, we couldn’t see anything. To help us see what’s going on, I’ve used the following command to convert each character to its decimal value.

(Get-ADComputer -Identity PTU730$ -Properties *).OperatingSystem -split"(?<=\G.{1})" | %  {            
    if ($_ -ne "")            
    {            
        $_ + "-> " + [int][char]$_            
    }            
}

character 160

I’ve copied the space between ‘Windows’ and ‘7’ from the edited field in the adsiedit.msc console and pasted it in the console.
Now, here is a tip to split a string using the “\s” that represents a regular expression matching any white space character instead of the simple space character.
character 160

Coloring WindowsUpdate.log

The other day I’ve seen the post about WinDump Color Highlighting PowerShell Script from Jason Fossen and thought that it could be very useful if the WindowsUpdate.log could be colored.

On February, there has been a problem with the Silverlight update that seemed to fail with error 80070643 but it was actually correctly installed.
Doug Neal from Microsoft Update explained on the patchmanagement.org distribution list that it was due to a detection logic error.

Here’s an extract how the error about Silverlight (MS12-016) is displayed using the colored extract of the WindowsUpdate.log
WU log extract

Later on, I’ve also found some explanations about How to read the Windowsupdate.log file.

I did not focus too much on performance (I’ve added a progress bar to see what’s going on) and I’ve added the ability to search either by a date or a string. Enjoy 🙂

#Requires -Version 2.0            
            
            
            
param(            
   [Parameter(ParameterSetName='Date', Mandatory=$true, Position=0)]            
    [System.DateTime]${Date},            
            
    [Parameter(ParameterSetName='DateString', Mandatory=$true, Position=0)]            
    [system.string]${DateString},            
            
    [Parameter(ParameterSetName='SearchString', Mandatory=$true, Position=0)]            
    [system.string]${SearchString}            
)            
            
            
if (Test-Path $env:systemroot\WindowsUpdate.log)            
{            
    $allcontent = Get-Content -Path $env:systemroot\WindowsUpdate.log            
} else {            
    Write-Host -ForegroundColor Red -Object ("Cannot find $env:systemroot\WindowsUpdate.log")            
    exit            
}            
            
switch ($PsCmdlet.ParameterSetName)            
{            
    Date {            
        $formatteddate = "{0:yyyy}-{1:MM}-{2:dd}" -f $Date,$Date,$Date            
    }            
    DateString {            
        if (($DateString -match "^\d{4}\-\d{2}\-\d{2}$") -or ($DateString -match "^\d{4}$") -or ($DateString -match "^\d{4}\-\d{2}"))            
        {            
            $formatteddate = $DateString            
        } else {            
            Write-Host -ForegroundColor Red -Object "The expected DateString format is yyyy-MM-dd"            
            exit            
        }            
    }            
}            
            
$parsedcontent = @()            
$count = 0            
foreach ($line in $allcontent)            
{            
    $count++            
    Write-Progress -activity "Parsing WindowsUpdate.log" -status "Percent added: " -PercentComplete (($count/$allcontent.Count)*100)            
            
    if ($formatteddate -ne $null)            
    {            
        if ($line.startswith($formatteddate))            
        {            
            # Add each line to our array            
            $parsedcontent += $line            
        }            
    }            
    if ($SearchString -ne $null)            
    {            
        if ($line -match [regex]::escape($SearchString))            
        {            
            # Add each line to our array            
            $parsedcontent += $line            
        }            
    }            
}            
            
$count = 0            
foreach ($line in $parsedcontent)            
{            
    $count++            
    Write-Progress -activity "Displaying colored WindowsUpdate.log" -status "Percent added: " -PercentComplete (($count/$parsedcontent.Count)*100)            
    # First split the line by Tabs            
    $arString = @($line -split ([char]9))            
    # Date and time            
    Write-Host -ForegroundColor Cyan -NoNewline -Object ($arString[0] + " " + $arString[1] +  " ")            
    # PID and TID            
    Write-Host -ForegroundColor Gray -NoNewline -Object ($arString[2] + " " + $arString[3] +  " ")            
    # Component            
    Write-Host -ForegroundColor Blue -NoNewline -Object ($arString[4] + " ")            
    # Text: get it as a single line            
    $restofline = -join ($arString[5..($arString.Count-1)])            
    switch ($restofline)            
    {            
        # Lines that match only a reptition of ":","*","-","+" or "#" that acts as line separators            
        {$_ -match [regex]'^[\:|\*|\-|\+|\#]+$'}        {Write-Host -ForegroundColor DarkGray -Object $_ -NoNewline}            
        # Only lines that begin by either ":","*","-","+","=" or "#"            
        {$_ -match [regex]'^[\:|\*|\-|\+|\=|\#]+\s{1}'} {Write-Host -ForegroundColor Cyan -Object $_ -NoNewline}            
        # Lines that begin by ">>-- "              
        {$_ -match [regex]'^>>\-\-\s{1}'}               {Write-Host -ForegroundColor Gray -Object $_ -NoNewline}            
        # Lines that begin by "  + "            
        {$_ -match [regex]'^\s{2,3}\+\s{1}.'}           {Write-Host -ForegroundColor DarkGray -Object $_ -NoNewline}            
        # Lines that begin by "  *       {"            
        {$_ -match [regex]'^\s{2,3}\*\s{7}\{.'}         {Write-Host -ForegroundColor DarkGray -Object $_ -NoNewline}            
        # Lines that begin by "  *   Title = "            
        {$_ -match [regex]'^\s{2,3}\*\s{3}Title\s=\s'}  {Write-Host -ForegroundColor White -Object $_ -NoNewline}            
        # Lines that begin by "  * Added update {"            
        {$_ -match [regex]'^\s{2,3}\*\s{1}Added\s{1}update\s{1}\{'} {Write-Host -ForegroundColor DarkGray -Object $_ -NoNewline}            
        default            
        {            
            # Now we split other lines and the remaining text by spaces            
            $arrestofline = @($restofline.split(([char]32)))            
            foreach ($t in $arrestofline)            
            {            
                switch($t)            
                {            
                    # Case sensitive match            
                    {$_ -cmatch "WARNING:"} {Write-Host -ForegroundColor Yellow   -Object $_ -NoNewline}            
                    {$_ -cmatch "FATAL:"}   {Write-Host -ForegroundColor Red      -Object $_ -NoNewline}            
                    # Any hexadecimal notation except 0x00000000 that may be followed by "." or ",".            
                    {$_.StartsWith("0x") -and ($_ -notmatch '^0x00000000([\.|\,]??)')}   {Write-Host -ForegroundColor Red -Object $_ -NoNewline}            
                    { ($_ -match '^0x00000000([\.|\,]??)')} {Write-Host -ForegroundColor Green    -Object $_ -NoNewline}            
                    # Match an hexadecimal number followed by "." or not.            
                    {$_ -match "^([0-9a-f]{8})((\.)??)$"}   {Write-Host -ForegroundColor Red      -Object $_ -NoNewline}            
                    # Match a number but a hexadecimal            
                    {$_ -match "^\d{1,7}(([,|\)])??)$"}     {Write-Host -ForegroundColor Magenta  -Object $_ -NoNewline}            
                    {$_ -match "^\d{9,20}(([,|\)])??)$"}    {Write-Host -ForegroundColor Magenta  -Object $_ -NoNewline}            
                    # Match a Date Time yyyy-MM-dd HH:mm:ss            
                    {$_ -match "^\d{4}\-\d{2}\-\d{2}$"}     {Write-Host -ForegroundColor White -Object $_ -NoNewline}            
                    {$_ -match "^\d{2}\:\d{2}\:\d{2}$"}     {Write-Host -ForegroundColor White -Object $_ -NoNewline}            
                    # Exact matches            
                    {$_ -eq 'state:0'} {Write-Host -ForegroundColor Green    -Object $_ -NoNewline}            
                    {$_ -eq 'hr=0x0'}  {Write-Host -ForegroundColor Green    -Object $_ -NoNewline}            
                    {$_ -eq 'True'}    {Write-Host -ForegroundColor Magenta  -Object $_ -NoNewline}            
                    {$_ -eq 'False'}   {Write-Host -ForegroundColor Magenta  -Object $_ -NoNewline}            
                    # Begins by 'Yes and might be followd by ",",";" or nothing            
                    {$_ -match '^Yes(([,|;])??)$'} {Write-Host -ForegroundColor Magenta -Object $_ -NoNewline}            
                    {$_ -match '^No(([,|;])??)$'}  {Write-Host -ForegroundColor Magenta -Object $_ -NoNewline}            
                    # Anything that matches a URL            
                    {$_.StartsWith("http://")}     {Write-Host -ForegroundColor Green   -Object $_ -NoNewline}            
                    {$_.StartsWith("https://")}    {Write-Host -ForegroundColor Green   -Object $_ -NoNewline}            
                    {$_ -eq '(00000000)'}          {Write-Host -ForegroundColor Green   -Object $_ -NoNewline}            
                    {$_ -match 'successfully'}     {Write-Host -ForegroundColor Green   -Object $_ -NoNewline}            
                    # Anything that matches the 'Succeeded' word followed by ",","]","." or nothing            
                    {$_ -match 'Succeeded(([,|\]\.])??)$'} {Write-Host -ForegroundColor Green -Object $_ -NoNewline}            
                    {$_ -match '^Failed(([,|\]\.])??)$'}   {Write-Host -ForegroundColor Red   -Object $_ -NoNewline}            
                    # A keyword that may begin by "(" or not and followed by 'hr=' and a repetition of numbers            
                    {$_ -match "^((\()??)hr=[0-9][0-9]+"}  {Write-Host -ForegroundColor Red   -Object $_ -NoNewline}            
                    # A path that contains the '\SoftwareDistribution\' keyword            
                    {$_ -match [regex]'\\SoftwareDistribution\\'} {Write-Host -ForegroundColor White -Object $_ -NoNewline}            
                    default {Write-Host -ForegroundColor DarkGray -Object $_ -NoNewline}            
                } # end if switch            
                Write-Host -ForegroundColor Yellow -Object " " -NoNewline            
            } # end of foreach            
        } # end of default            
    } # end of switch            
    # Now insert a 'new line'            
    Write-Host -Object ([char]10)            
}            

PSH3 Workflow resources

When Windows PowerShell Met Workflow by PowerShell Team (introduction)

WMF3 CTP2 Windows PowerShell Workflow.pdf (already published a few months ago)

Video: Bruce Payette – PowerShell Workflows @Frankfurt Deep Dive conference

Windows PowerShell Workflow Module documentation on technet

Writing a Windows PowerShell Workflow (MSDN documentation)

Microsoft.PowerShell.Workflow Namespace documentation on MSDN

What happened to special characters

In powershell v3 beta, the backtick still escapes characters but there aren’t any special characters anymore ?:

In V2 you have:
special characters V2
Whereas in V3 you have:
special characters v3

The technet page about special characters in powershell v2 says that:

The following special characters are recognized by Windows PowerShell:

`0 Null
`a Alert
`b Backspace
`f Form feed
`n New line
`r Carriage return
`t Horizontal tab
`v Vertical tab
These characters are case-sensitive.

In V3 we actually need to either use quotes around special characters like this

Write-Host "`n"

or we can use the corresponding ascii table characters:

`0 Null -> [char]0
`a Alert -> [char]7
`b Backspace -> [char]8
`f Form feed -> [char]12
`n New line -> [char]10
`r Carriage return -> [char]13
`t Horizontal tab -> [char]9
`v Vertical tab -> [char]11

and we can now do:

Write-Host ([char]10)            
Write-Host ("test" + [char]9 + "tab")

Inside the new CIM command type

One of my favorite tip in powershell V2 is the following command that shows the code behind the tab completion feature:

(dir Function:\TabExpansion).Definition

Now, in powershell 3 beta on Windows 8, there’s a new cmdlet type called CIM. Once you have invoked a CIM cmdlet, you can explore its code.
Here’s how to see how many CIM cmdlets there are per module:

Get-Command -Capability CIM | Group-Object -Property ModuleName

Here’s how to explore the code of the new Get-NetIPAddress

(dir Function:\Get-NetIPAddress).Definition

and the code behind:


    [CmdletBinding(DefaultParameterSetName='ByIPv4', PositionalBinding=$false)]
    [OutputType([Microsoft.Management.Infrastructure.CimInstance])]
[OutputType('Microsoft.Management.Infrastructure.CimInstance#ROOT/StandardCimv2/MSFT_NetIPAddress')]

    param(
    
    [Parameter(ParameterSetName='ByIPv4')]
    [ValidateNotNull()]
    [string[]]
    ${IPv4Address},

    [Parameter(ParameterSetName='ByIPv6')]
    [ValidateNotNull()]
    [string[]]
    ${IPv6Address},

    [Parameter(ParameterSetName='ByIPv4', ValueFromPipeline=$true, ValueFromPipelineByPropertyName=$true)]
    [Parameter(ParameterSetName='ByIPv6', ValueFromPipeline=$true, ValueFromPipelineByPropertyName=$true)]
    [Alias('ifIndex')]
    [ValidateNotNull()]
    [System.UInt32[]]
    ${InterfaceIndex},

    [Parameter(ParameterSetName='ByIPv4', ValueFromPipelineByPropertyName=$true)]
    [Parameter(ParameterSetName='ByIPv6', ValueFromPipelineByPropertyName=$true)]
    [Alias('ifAlias')]
    [ValidateNotNull()]
    [string[]]
    ${InterfaceAlias},

    [Parameter(ParameterSetName='ByIPv4')]
    [Parameter(ParameterSetName='ByIPv6')]
    [ValidateNotNull()]
    [Microsoft.PowerShell.Cmdletization.GeneratedTypes.NetIPAddress.AddressFamily[]]
    ${AddressFamily},

    [Parameter(ParameterSetName='ByIPv4')]
    [Parameter(ParameterSetName='ByIPv6')]
    [ValidateNotNull()]
    [Microsoft.PowerShell.Cmdletization.GeneratedTypes.NetIPAddress.Type[]]
    ${Type},

    [Parameter(ParameterSetName='ByIPv4')]
    [Parameter(ParameterSetName='ByIPv6')]
    [ValidateNotNull()]
    [byte[]]
    ${PrefixLength},

    [Parameter(ParameterSetName='ByIPv4')]
    [Parameter(ParameterSetName='ByIPv6')]
    [ValidateNotNull()]
    [Microsoft.PowerShell.Cmdletization.GeneratedTypes.NetIPAddress.PrefixOrigin[]]
    ${PrefixOrigin},

    [Parameter(ParameterSetName='ByIPv4')]
    [Parameter(ParameterSetName='ByIPv6')]
    [ValidateNotNull()]
    [Microsoft.PowerShell.Cmdletization.GeneratedTypes.NetIPAddress.SuffixOrigin[]]
    ${SuffixOrigin},

    [Parameter(ParameterSetName='ByIPv4')]
    [Parameter(ParameterSetName='ByIPv6')]
    [ValidateNotNull()]
    [Microsoft.PowerShell.Cmdletization.GeneratedTypes.NetIPAddress.AddressState[]]
    ${AddressState},

    [Parameter(ParameterSetName='ByIPv4')]
    [Parameter(ParameterSetName='ByIPv6')]
    [ValidateNotNull()]
    [System.TimeSpan[]]
    ${ValidLifetime},

    [Parameter(ParameterSetName='ByIPv4')]
    [Parameter(ParameterSetName='ByIPv6')]
    [ValidateNotNull()]
    [System.TimeSpan[]]
    ${PreferredLifetime},

    [Parameter(ParameterSetName='ByIPv4')]
    [Parameter(ParameterSetName='ByIPv6')]
    [ValidateNotNull()]
    [bool[]]
    ${SkipAsSource},

    [Parameter(ParameterSetName='ByIPv4')]
    [Parameter(ParameterSetName='ByIPv6')]
    [ValidateNotNull()]
    [Microsoft.PowerShell.Cmdletization.GeneratedTypes.NetIPAddress.Store[]]
    ${Store},

    [Parameter(ParameterSetName='ByIPv4', ValueFromPipeline=$true)]
    [Parameter(ParameterSetName='ByIPv6', ValueFromPipeline=$true)]
    [PSTypeName('Microsoft.Management.Infrastructure.CimInstance#root/standardcimv2/MSFT_NetIPInterface')]
    [ValidateNotNull()]
    [Microsoft.Management.Infrastructure.CimInstance]
    ${AssociatedIPInterface},

    [Parameter(ParameterSetName='ByIPv4')]
    [Parameter(ParameterSetName='ByIPv6')]
    [Alias('Session')]
    [ValidateNotNullOrEmpty()]
    [Microsoft.Management.Infrastructure.CimSession[]]
    ${CimSession},

    [Parameter(ParameterSetName='ByIPv4')]
    [Parameter(ParameterSetName='ByIPv6')]
    [int]
    ${ThrottleLimit},

    [Parameter(ParameterSetName='ByIPv4')]
    [Parameter(ParameterSetName='ByIPv6')]
    [switch]
    ${AsJob})

    DynamicParam {
        try 
        {
            if (-not $__cmdletization_exceptionHasBeenThrown)
            {
                $__cmdletization_objectModelWrapper = Microsoft.PowerShell.Utility\New-Object $script:ObjectModelWrapper
                $__cmdletization_objectModelWrapper.Initialize($PSCmdlet, $script:ClassName, $script:ClassVersion, $script:ModuleVersion, $script:PrivateData)

                if ($__cmdletization_objectModelWrapper -is [System.Management.Automation.IDynamicParameters])
                {
                    ([System.Management.Automation.IDynamicParameters]$__cmdletization_objectModelWrapper).GetDynamicParameters()
                }
            }
        }
        catch
        {
            $__cmdletization_exceptionHasBeenThrown = $true
            throw
        }
    }

    Begin {
        $__cmdletization_exceptionHasBeenThrown = $false
        try 
        {
            __cmdletization_BindCommonParameters $__cmdletization_objectModelWrapper $PSBoundParameters
            $__cmdletization_objectModelWrapper.BeginProcessing()
        }
        catch
        {
            $__cmdletization_exceptionHasBeenThrown = $true
            throw
        }
    }
        

    Process {
        try 
        {
            if (-not $__cmdletization_exceptionHasBeenThrown)
            {
    $__cmdletization_queryBuilder = $__cmdletization_objectModelWrapper.GetQueryBuilder()
    if ($PSBoundParameters.ContainsKey('IPv4Address') -and (@('ByIPv4') -contains $PSCmdlet.ParameterSetName )) {
        $__cmdletization_values = @(${IPv4Address})
        $__cmdletization_queryBuilder.FilterByProperty('IPv4Address', $__cmdletization_values, $true, 'Default')
    }
    if ($PSBoundParameters.ContainsKey('IPv6Address') -and (@('ByIPv6') -contains $PSCmdlet.ParameterSetName )) {
        $__cmdletization_values = @(${IPv6Address})
        $__cmdletization_queryBuilder.FilterByProperty('IPv6Address', $__cmdletization_values, $true, 'Default')
    }
    if ($PSBoundParameters.ContainsKey('InterfaceIndex') -and (@('ByIPv4', 'ByIPv6') -contains $PSCmdlet.ParameterSetName )) {
        $__cmdletization_values = @(${InterfaceIndex})
        $__cmdletization_queryBuilder.FilterByProperty('InterfaceIndex', $__cmdletization_values, $false, 'Default')
    }
    if ($PSBoundParameters.ContainsKey('InterfaceAlias') -and (@('ByIPv4', 'ByIPv6') -contains $PSCmdlet.ParameterSetName )) {
        $__cmdletization_values = @(${InterfaceAlias})
        $__cmdletization_queryBuilder.FilterByProperty('InterfaceAlias', $__cmdletization_values, $true, 'Default')
    }
    if ($PSBoundParameters.ContainsKey('AddressFamily') -and (@('ByIPv4', 'ByIPv6') -contains $PSCmdlet.ParameterSetName )) {
        $__cmdletization_values = @(${AddressFamily})
        $__cmdletization_queryBuilder.FilterByProperty('AddressFamily', $__cmdletization_values, $false, 'Default')
    }
    if ($PSBoundParameters.ContainsKey('Type') -and (@('ByIPv4', 'ByIPv6') -contains $PSCmdlet.ParameterSetName )) {
        $__cmdletization_values = @(${Type})
        $__cmdletization_queryBuilder.FilterByProperty('Type', $__cmdletization_values, $false, 'Default')
    }
    if ($PSBoundParameters.ContainsKey('PrefixLength') -and (@('ByIPv4', 'ByIPv6') -contains $PSCmdlet.ParameterSetName )) {
        $__cmdletization_values = @(${PrefixLength})
        $__cmdletization_queryBuilder.FilterByProperty('PrefixLength', $__cmdletization_values, $false, 'Default')
    }
    if ($PSBoundParameters.ContainsKey('PrefixOrigin') -and (@('ByIPv4', 'ByIPv6') -contains $PSCmdlet.ParameterSetName )) {
        $__cmdletization_values = @(${PrefixOrigin})
        $__cmdletization_queryBuilder.FilterByProperty('PrefixOrigin', $__cmdletization_values, $false, 'Default')
    }
    if ($PSBoundParameters.ContainsKey('SuffixOrigin') -and (@('ByIPv4', 'ByIPv6') -contains $PSCmdlet.ParameterSetName )) {
        $__cmdletization_values = @(${SuffixOrigin})
        $__cmdletization_queryBuilder.FilterByProperty('SuffixOrigin', $__cmdletization_values, $false, 'Default')
    }
    if ($PSBoundParameters.ContainsKey('AddressState') -and (@('ByIPv4', 'ByIPv6') -contains $PSCmdlet.ParameterSetName )) {
        $__cmdletization_values = @(${AddressState})
        $__cmdletization_queryBuilder.FilterByProperty('AddressState', $__cmdletization_values, $false, 'Default')
    }
    if ($PSBoundParameters.ContainsKey('ValidLifetime') -and (@('ByIPv4', 'ByIPv6') -contains $PSCmdlet.ParameterSetName )) {
        $__cmdletization_values = @(${ValidLifetime})
        $__cmdletization_queryBuilder.FilterByProperty('ValidLifetime', $__cmdletization_values, $false, 'Default')
    }
    if ($PSBoundParameters.ContainsKey('PreferredLifetime') -and (@('ByIPv4', 'ByIPv6') -contains $PSCmdlet.ParameterSetName )) {
        $__cmdletization_values = @(${PreferredLifetime})
        $__cmdletization_queryBuilder.FilterByProperty('PreferredLifetime', $__cmdletization_values, $false, 'Default')
    }
    if ($PSBoundParameters.ContainsKey('SkipAsSource') -and (@('ByIPv4', 'ByIPv6') -contains $PSCmdlet.ParameterSetName )) {
        $__cmdletization_values = @(${SkipAsSource})
        $__cmdletization_queryBuilder.FilterByProperty('SkipAsSource', $__cmdletization_values, $false, 'Default')
    }
    if ($PSBoundParameters.ContainsKey('Store') -and (@('ByIPv4', 'ByIPv6') -contains $PSCmdlet.ParameterSetName )) {
        $__cmdletization_values = @(${Store})
        $__cmdletization_queryBuilder.FilterByProperty('Store', $__cmdletization_values, $false, 'Default')
    }
    if ($PSBoundParameters.ContainsKey('AssociatedIPInterface') -and (@('ByIPv4', 'ByIPv6') -contains $PSCmdlet.ParameterSetName )) {
    $__cmdletization_queryBuilder.FilterByAssociatedInstance(${AssociatedIPInterface}, 'MSFT_NetIPInterfaceIPAddress', 'Antecedent', 'Dependent', 'Default')
    }


    $__cmdletization_objectModelWrapper.ProcessRecord($__cmdletization_queryBuilder)
            }
        }
        catch
        {
            $__cmdletization_exceptionHasBeenThrown = $true
            throw
        }
    }
        

    End {
        try
        {
            if (-not $__cmdletization_exceptionHasBeenThrown)
            {
                $__cmdletization_objectModelWrapper.EndProcessing()
            }
        }
        catch
        {
            throw
        }
    }
    # .EXTERNALHELP MSFT_NetIPAddress.cdxml-Help.xml

Finding all parameters

I’ve tested powershell v3 ctp2 and beta and noticed that the following command provided by this tips page still fails:

Get-Command -CommandType Cmdlet | Select-Object -ExpandProperty Parameters |  ForEach-Object { $_.Keys } | Group-Object -NoElement | Sort-Object Count, Name -Descending

get-command bug

Joel Bennett explained in his blog post why it fails. To make it short, it’s due to the fact that modules are preloaded (new feature in powershell 3) when you invoke cmdlets but not when you use the Get-command cmdlet.

The above command won’t fail if all modules are loaded. Here’s how to load all modules

Get-Module -ListAvailable | % { ipmo -Name $_.Name}

Inside System.Net.HttpWebRequest webproxy

  • Context:

I’ve logged on interactively with an administrative user A in a corporate environment, defined the proxy in Internet Explorer using the GUI, browsed the web, logged off and connected with user B, put the laptop into hibernation, brought the laptop at home, made a session reconnect with user B and finally launched a powershell console running as user A (as he has administrative credential on the laptop).

  • Problem:

Whenever I try to use the Invoke-Webrequest or Invoke-RestMethod, it ends with the following error: “Invoke-WebRequest : The proxy name could not be resolved:” invoke-webrequest error 01

  • Debugging steps:

So I’ve had a look at the stack trace that contains the most recent error but I got no clue:

$StackTrace

invoke-webrequest stacktrace 01

Trying to make the system fail to understand what’s going on is sometimes useful while troubleshooting.
I’ve tried to set a null proxy to override the corporate proxy adress that seems to be picked up automatically from somewhere:

Invoke-WebRequest "http://www.google.com" -Proxy [system.URI]''

I got the following:
invoke-webrequest error 02

I’ve looked at the new $PSDefaultParameterValues variable in powershell 3 and checked that a proxy parameter wasn’t defined.
I’ve then tried to define a null proxy for the Invoke-WebRequest cmdlet

$PSDefaultParameterValues += @{"Invoke-WebRequest:Proxy"=[system.URI]''}

Now when I do:

Invoke-WebRequest "http://www.google.com"

I’ve still got the same error as above: “Invoke-WebRequest : This operation is not supported for a relative URI.”

Great, this shows that I’ve been able to override the default user defined proxy but wasn’t able to set the proxy settings to none.
So I removed the default proxy setting I’ve set:

$PSDefaultParameterValues.Remove("Invoke-WebRequest:Proxy")

Then the following method on the system.net.webproxy .net object shows me the corporate proxy being defined

[system.net.webproxy]::GetDefaultProxy()

But it doesn’t have any method to reset it to ‘none’

[system.net.webproxy] | gm -MemberType Method -Static

Note also that it’s deprecated.

Having a look to the suggested .net object system.net.webrequest confirms that:

The DefaultWebProxy property reads proxy settings from the app.config file.
If there is no config file, the current user’s Internet Explorer (IE) proxy settings are used.

To make sure there isn’t any app.config file., I quickly did

Get-ChildItem $env:systemdrive\app.config -Recurse

I finally remembered the context and when I’ve read first line of the following article I came up with the solution.

$BinaryArray = (Get-ItemProperty 'HKCU:\Software\Microsoft\Windows\CurrentVersion\Internet Settings\Connections').DefaultConnectionSettings            

-join ($BinaryArray | % { [char][int]"$_"})            

Remove-ItemProperty -Path 'HKCU:\Software\Microsoft\Windows\CurrentVersion\Internet Settings\Connections' -Name DefaultConnectionSettings

Voilà, now the following works:

Invoke-WebRequest -Uri "http://www.google.com"
  • Lessons learned
    • Powershell 3 automatically uses the proxy defined in the current user profile unless there’s a machine level (ProxySettingsPerUser) defined that tells not to.
    • I haven’t found a way to override this setting by providing an explicit proxy parameter set to ‘none’. If anyone knows how to do it, pls let us know.
    • The new default parameter $PSDefaultParameterValues is interesting and should be tested systematically while troubleshooting or using cmdlets w/o parameters inside scripts