Function to invoke PowerShell ISE from shell

Another little function to add to your PowerShell profile.

If you’re in the PowerShell Integrated Scripting Environment you can use the command

psedit <filename>

to open the file in the ISE editor – and it doesn’t just have to be a .ps1 file, it’ll open anything.

But if you have a regular PowerShell prompt open, psedit doesn’t work. Until now!

function psedit ($Filename){
    & "$env:SystemRoot\System32\WindowsPowerShell\v1.0\powershell_ise.exe" $Filename
}

It’ll also work if you just type psedit with no filename, and will open a new tab in the editor.

Posted in PowerShell | Tagged , , , | Leave a comment

Get Uptime with Get-Uptime

I’ve been using this for ages, and have now finally got around to a) blogging it, and b) updating it to use Get-CimInstance. The latter makes it particularly easy to code and thus makes the function very compact due to the way it “nicely” handles the date.

So here it is in all its glory (!):

function Get-Uptime ([string]$ComputerName = $env:COMPUTERNAME){
    (Get-Date) - (Get-CimInstance -ClassName Win32_OperatingSystem -ComputerName $ComputerName).LastBootUpTime
}

It’ll default to the local computer unless you specify -ComputerName when calling it.

Personally, I have this in my PowerShell profile, so that it’s always available for use.

As you can see, it compares the LastBootUpTime property from the Win32_OperatingSystem CIM object with the current date & time and returns the difference (as an object – so you can do stuff with it like pipe it to Select-Object etc.).

The output looks something like:

Days              : 7
Hours             : 4
Minutes           : 15
Seconds           : 54
Milliseconds      : 139
Ticks             : 6201541391309
TotalDays         : 7.17770994364468
TotalHours        : 172.265038647472
TotalMinutes      : 10335.9023188483
TotalSeconds      : 620154.1391309
TotalMilliseconds : 620154139.1309

I’ll leave it as an exercise for the reader to make it work across time zones (it really won’t take you much effort!).

Posted in PowerShell | Tagged , , , , , , | Leave a comment

Remote PowerShell to an IP Address

PowerShell remoting works over the WS-Man protocol, which in Windows is implemented via WinRM. By default this uses Kerberos authentication, and in most domain environments everything “just works”.

If the machine isn’t correctly registered in DNS you’ll get an error:

Enter-PSSession : Connecting to remote server server001 failed with the following error message : WinRM cannot process
the request. The following error with errorcode 0x80090322 occurred while using Kerberos authentication: An unknown
security error occurred.
 Possible causes are:
  -The user name or password specified are invalid.
  -Kerberos is used when no authentication method and no user name are specified.
  -Kerberos accepts domain user names, but not local user names.
  -The Service Principal Name (SPN) for the remote computer name and port does not exist.
  -The client and remote computers are in different domains and there is no trust between the two domains.
 After checking for the above issues, try the following:
  -Check the Event Viewer for events related to authentication.
  -Change the authentication method; add the destination computer to the WinRM TrustedHosts configuration setting or
use HTTPS transport.
 Note that computers in the TrustedHosts list might not be authenticated.
   -For more information about WinRM configuration, run the following command: winrm help config. For more
information, see the about_Remote_Troubleshooting Help topic.
At line:1 char:1
+ Enter-PSSession -ComputerName server001
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    + CategoryInfo          : InvalidArgument: (server001:String) [Enter-PSSession], PSRemotingTransportException
    + FullyQualifiedErrorId : CreateRemoteRunspaceFailed

As a result, or in another scenario, you may have the need to connect via a machine’s IP address instead of it’s name. This, by default, won’t work either and you’ll get a different error:

Enter-PSSession : Connecting to remote server 192.168.1.202 failed with the following error message : The WinRM client
cannot process the request. Default authentication may be used with an IP address under the following conditions: the
transport is HTTPS or the destination is in the TrustedHosts list, and explicit credentials are provided. Use
winrm.cmd to configure TrustedHosts. Note that computers in the TrustedHosts list might not be authenticated. For more
information on how to set TrustedHosts run the following command: winrm help config. For more information, see the
about_Remote_Troubleshooting Help topic.
At line:1 char:1
+ Enter-PSSession -ComputerName 192.168.1.202
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    + CategoryInfo          : InvalidArgument: (192.168.1.202:String) [Enter-PSSession], PSRemotingTransportException
    + FullyQualifiedErrorId : CreateRemoteRunspaceFailed

The fix for this is, as the error test suggests, to add the remote machine’s IP address to the TrustedHosts list, as follows:

Open an elevated PowerShell prompt and type:

Set-Item wsman:\localhost\Client\TrustedHosts -value 192.168.1.202

Then from a regular PS session:

Enter-PSSession -ComputerName 192.168.1.202 -Credential (Get-Credential -UserName rcmtech\rcm-admin -Message "gimme the password")

Note that you have to specify credentials, per the example above.

Posted in PowerShell | Tagged , , , , , , | Leave a comment

Find out what’s really happening in your network with LogRhythm NetMon Freemium

I recently discovered that LogRhythm, as well as very a full-featured Security Intelligence Platform and SIEM, also provide a “freemium” Network Monitor. The “freemium” refers to that fact that the software is 100% free, full-featured and not time-limited, but is capacity-limited. Those limits are 1Gbps of network bandwith and three days of history.

Those limits are fine for if you don’t already have anything like this currently running in your network, and depending on what kind of stuff you pump over your network, for the average small office they’ll be fine and give you some great insights into what’s going on.

Setup

The hardware requirements state that the system should have a minimum of 8GB RAM (12GB recommended), 4 CPU cores (minimum of 2), and unless you just want to monitor traffic from the NetMon box itself you’ll need two NICs.

NetMon freemium is available to download either as a VirtualBox VM, or as an ISO image. I chose the ISO option as I had an old Dell PowerEdge 2950 lying around so decided to run the software on that. I tried using Rufus but could not get it to boot properly, so I gave up and burnt the ISO onto a DVD.

I’d recommend plugging one of your two NICs into a network with DHCP enabled, and leave the other one disconnected initially. NetMon is based upon CentOS 7, and installation is really straightforward.

Once installed, you’ll be given a logon prompt. Log in as logrhythm with a password of changeme. Use the command:
ip address
to see what IP address has been obtained from DHCP – look for the line beginning inet in a section with eth near the beginning, e.g. 2: eth0. If DHCP didn’t work, reboot to get it to try again. Then from a web browser, open https://<ip address> and you’ll get a LogRhythm sign in page. (If you get a pop-up authentication box, just click Cancel on it, I’m not sure why this sometimes appears). The web-based credentials default to a username of admin and a password of changeme. Change the password.

Now connect the second NIC to your switch. From the NetMon GUI, go to Configuration – Engine, and set the Input Interface. This should be set to one of the options starting netmap, I only had one: netmap:eno2 so I picked this. Click Apply Changes then go to Diagnostics – Interface and start to watch the Packet Rate graph, this updates every few seconds so you can see the data start to arrive once you’ve done the network configuration on your switch.

I’ve configured the switch port to be in Switched Port ANalyser mode (SPAN), which is a way of sending all the traffic from one port or more ports or VLANs to another port. My office PCs are all on a particular VLAN so I’ve chosen to send all this traffic to my SPAN port. On a Cisco switch you do this by creating a monitor session. You can have multiple ones of these, and you may already have some set up, so first check what you have:

en
sh run | inc monitor

and you may be shown some lines such as:

monitor session 1 source interface Gi1/0/2 , Gi1/0/4
monitor session 1 destination interface Gi1/0/46

This means that in order to create a new monitor session, I have to use session 2, as session 1 is already in use. NIC2 of my server is plugged into port Gi1/0/47, and aside from a description, there is no other configuration on this switch port. To send all VLAN10 traffic to this port I used the commands:

conf t
monitor session 2 source vlan 10 both
monitor session 2 destination interface g1/0/47

At this point I saw the Received line jump up from zero in the Packet Rate graph, so I knew the command had worked and NetMon was receiving data.

Analyse your data

So now you’re getting data, and by clicking on the LogRhythm logo you’ll be taken to the dashboard, by default showing you:

  • Top Applications by Bandwidth (histogram)
  • Top Applications by Bandwidth (pie)
  • Top Applications by Packet Count (pie)
  • Analyze table

This gives a good overview of what’s happening right now on your network. You can click into the pie chart sections to filter data immediately, or click onto a section of the histogram to build a filter that sets the protocol and time range to give you more detail. For example, what’s all that smb traffic at 11:43? Click the pale blue section of the bar, click Apply Now and I get the timeline broken down into five second slots, and the Analyze Table lets me go through the sessions and see what was talking to what. I can see more information by clicking the “up” arrow just underneath the histogram, this gives me a table which shows the amount of data sent by the selected protocol per second:

Click on the date on one of these rows, e.g. the one where 72.326MB was transferred, and it’ll filter again to that time but at 100ms granularity. I now only have one entry in the Analyze Table at the bottom, and can not only see the source and destination IP addresses (sadly it doesn’t convert these into DNS names). By expanding the line in the Analyze Table, I can see lots of info, most interestingly (because this is the SMB protocol) a list of all the filenames accessed. In my case, I can now see that this traffic was caused by a machine doing a full Active Directory Group Policy refresh, which is perfectly normal.

Over to you

I’ve found this product to be pretty good, it’s giving me insight into something that I had no visibility of until now, and I suspect most people would find the same. There are a lot more features that I’ve not looked at yet, such as alarms, customising dashboards, charts and tables.

There are some videos showing how to use NetMon on LogRhythm’s YouTube channel, and there’s also a community site you can sign up to for free for more resources and to ask for help. All in all, NetMon Freemium is going to be a nice additional tool for keeping an eye on my systems and data.

Posted in Networking, Security | Tagged , , , , , , , , , , , , , , , | Leave a comment

PowerShell Transcription to a file share breaks everything, and how to fix it

There’s been a bit of noise about PowerShell-based malware recently, and given the “assume breach” security mindset, I thought it was about time I enabled some of the PowerShell logging features in Windows. The basis behind “assume breach” is that you assume that your network security has already been breached and there are unauthorised things going on in your environment. The trick is to put in place suitable logging and monitoring to be able to detect and trace that activity.

The definitive source for PowerShell security config seems to still be the PowerShell (heart) the Blue Team blog post from mid-2015. This gives a lot of good info about what security features are available in PowerShell 5.0 and how to enable them in a sensible way. Most of them can be configured by Group Policy, e.g. transcription is enabled and configured via “Turn on PowerShell Transcription” in Windows Components – Administrative Templates – Windows PowerShell.

Based on that, and other things I’d read, PowerShell transcription to a network share seemed like exactly what I should have turned on. It gives you a detailed text log of everything that occurs in a PowerShell session, logged to an off-the-box location. Very handy.

So I turned it on.

And lots of things broke.

Enter-PSSession : Processing data from remote server ServerA failed with the following error message:
Could not find a part of the path '\\ServerB.rcmtech.co.uk\PowerShellTranscript$'. For more information, see the
about_Remote_Troubleshooting Help topic.
At line:1 char:1
+ enter-pssession -ComputerName ServerA
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ CategoryInfo          : InvalidArgument: (Server01:String) [Enter-PSSession], PSRemotingTransportException
+ FullyQualifiedErrorId : CreateRemoteRunspaceFailed

The problem seems to be with how I admin my servers (remotely, not on the console) and how the transcription feature works.

The root of my problems seem to be Kerberos double-hop authentication.

Consider how you might have done similar things in the past:

  • From your PC, remote desktop onto ServerA, access a share on ServerB. No problems.
  • From your PC, run PSExec to get a remote command prompt on ServerA, access a share on ServerB. No problems.
  • Set the logging folder of a service running as NT Authority\System on ServerA to write to a UNC path on ServerB, having granted the account ServerA$ permission to the share and granted NTFS permissions to the folder. No problems.
  • Forwarded Windows Event Logs from ServerA to ServerB, and noticed how details of people interacting with ServerA appeared in Forwarded Events on ServerB. No problems.

So why is PowerShell transcription different? The transcription is done by delegation of the credentials from my PC by ServerA and using those to try to access the share on ServerB. This won’t work: assume I’m running PowerShell as an admin on my PC (OK, not best practice, but fixing that is going to take a long time) and that I then run the following command:

Invoke-Command -ComputerName ServerA -ScriptBlock {Get-ChildItem -Path \\ServerB\c$}

This will fail with an Access is Denied (PermissionDenied) error.

There are various ways to make the double-hop work. As far as I can tell, the best balance of security and ease of use is to use Resource-Based Kerberos Constrained Delegation.

This works by configuring the Active Directory computer object of ServerB to allow it to accept delegated credentials via ServerA:

Set-ADComputer -Identity ServerB -PrincipalsAllowedToDelegateToAccount (Get-ADComputer -Identity ServerA)

Possibly followed by running the following on ServerA:

klist purge -li 0x3e7

but only if you’d tried and failed to use delegated credentials from ServerA in the past 15 minutes. If you’d not tried to do that, the klist command is unecessary.

Also, annoyingly, this method will not allow you to enter a remote session from your PC to ServerA and then create a remote session from ServerA to ServerB. Resource-based Kerberos constrained delegation does not support WinRM, you’ll get a 0x8009030e error (a specified logon session does not exist).

So if you want all your servers to send their PowerShell transcripts to ServerB, you need to add all your servers to the list of PrincipalsAllowedToDelegateToAccount for ServerB, and keep adding new servers to that list as they are created. Pain in the neck.

How I’d like transcription to work is that the transcripts are written by the computer account where the PowerShell is being executed. I would have thought that this was possible, because the computer account is the NT Authority\System account, and that is as powerful and privileged an account as you can get in Windows. That way I would just configure the transcripts file share to have write access for the Domain Computers group, and everything would be well with the world.

Posted in PowerShell, Security | Tagged , , , , , , , , , , , | Leave a comment

Collect user and group SIDs and names from Active Directory

Ever found yourself looking through the Access Control List of a file/folder/share and mixed in along with the group names (hopefully not user names!) you see some SIDs? These look something like S-1-5-21-0123456789-0123456789-0123456789-0123.
These are the Security IDs of deleted groups and users. Wouldn’t it be handy to have a list of these so you could work out what it was that used to have permission, but that’s now been deleted? Yes it would, so I wrote a basic PowerShell script to collect all the SIDs and user names and store them in an XML file. It also has a field for whather the item is a user or a group, and also the date and time the item was added.
You can run the script as a regular user, but will need to AD PowerShell cmdlets installed (possibly via RSAT if on a client OS).

$XMLFile = "C:\Users\Public\Documents\UsersAndGroups.xml"
# Get users and groups from AD
$ADUsers = Get-ADUser -Filter * | Select-Object -Property Name,SID
$ADGroups = Get-ADGroup -Filter * | Select-Object -Property Name,SID
# Create an array to store AD users and groups
$UsersAndGroups = New-Object -TypeName System.Collections.ArrayList
# Add users to array
foreach($User in $ADUsers){
    $ThisUser = New-Object -TypeName System.Object
    Add-Member -InputObject $ThisUser -MemberType NoteProperty -Name SID -Value $User.SID.Value
    Add-Member -InputObject $ThisUser -MemberType NoteProperty -Name Name -Value $User.Name
    Add-Member -InputObject $ThisUser -MemberType NoteProperty -Name Type -Value "User"
    Add-Member -InputObject $ThisUser -MemberType NoteProperty -Name DateAdded -Value (Get-Date -Format s)
    $UsersAndGroups.Add($ThisUser) | Out-Null
}
# Add groups to array
foreach($Group in $ADGroups){
    $ThisGroup = New-Object -TypeName System.Object
    Add-Member -InputObject $ThisGroup -MemberType NoteProperty -Name SID -Value $Group.SID.Value
    Add-Member -InputObject $ThisGroup -MemberType NoteProperty -Name Name -Value $Group.Name
    Add-Member -InputObject $ThisGroup -MemberType NoteProperty -Name Type -Value "Group"
    Add-Member -InputObject $ThisGroup -MemberType NoteProperty -Name DateAdded -Value (Get-Date -Format s)
    $UsersAndGroups.Add($ThisGroup) | Out-Null
}
$UsersAndGroups.Count
# Get existing data if it already exists
if(Test-Path -Path $XMLFile){
    $XMLData = Import-Clixml -Path $XMLFile
    $XMLDataArrayList = New-Object -TypeName System.Collections.ArrayList
    $XMLDataArrayList.AddRange($XMLData)
    $XMLDataArrayList.Count
    # Update existing data with new SIDs
    foreach($Item in $UsersAndGroups){
        if($XMLData.SID -contains $Item.SID){
            #Write-Host $Item.SID -ForegroundColor Green
        }else{
            Write-Host $Item.SID -ForegroundColor Red
            $XMLDataArrayList.Add($Item) | Out-Null
        }
    }
    # Write updated data back to XML file
    $XMLDataArrayList | Export-Clixml -Path $XMLFile
}else{
    # Write first time data to XML file
    $UsersAndGroups | Export-Clixml -Path $XMLFile
}

To view the file, and be able to easily search it, just use:

Import-Clixml -Path "C:\Users\Public\Documents\UsersAndGroups.xml" | Out-GridView
Posted in PowerShell, Security, Windows | Tagged , , , , , , | Leave a comment

PowerShell Exchange mailbox move progress monitor

This is a very basic script that’ll give you a progress bar to monitor a mailbox move process. You’ll need to run it from an Exchange Management Shell PowerShell prompt.

param([string]$Identity = "")
$Stats = Get-MoveRequestStatistics -Identity $Identity
do
{
    $Stats = Get-MoveRequestStatistics -Identity $Identity
    Write-Progress -Activity "Moving $Identity" -Status ([string]$Stats.BytesTransferred+" transferred of "+[string]$Stats.TotalMailboxSize) -PercentComplete $Stats.PercentComplete
    Start-Sleep -Milliseconds 500
}
while (($Stats.PercentComplete -le 99) -and ($Stats.Status -eq "InProgress"))
do
{
    $Stats = Get-MoveRequestStatistics -Identity $Identity
    Write-Progress -Activity "Moving $Identity" -Status $Stats.Status -PercentComplete 100
    Start-Sleep -Milliseconds 500
}
while ($Stats.StatusDetail -ne "Completed")
$Stats.StatusDetail
Posted in Exchange, PowerShell | Tagged , , , , , , , | Leave a comment

Change BitLocker Recovery Password with PowerShell

When BitLocker detects certain changes to the computer it’ll trigger Recovery Mode, and prompt for the Recovery Password. Likewise, you also need the recovery password if you need to access the encrypted disk from another machine or via Windows Recovery Environment (Windows RE).

If you need to provide your users with their BitLocker recovery password, you might want to change it afterwards. It allows them to get into the disk via alternative methods and thus bypass NTFS security. This is a bad thing.

If you have BitLocker set up right, it’ll write any new recovery passwords that it generates to Active Directory. Therefore the script (which you might want to run as a scheduled task, even if only on demand) does not display the new recovery password to screen. You can easily modify it to show the password by removing “-WarningAction SilentlyContinue”.

$MountPoint = "C:"
# Register the event log source
$LogSource = "RCMTech"
New-EventLog -LogName Application -Source $LogSource -ErrorAction SilentlyContinue
# Get the key protectors
$KeyProtectors = (Get-BitLockerVolume -MountPoint $MountPoint).KeyProtector
foreach($KeyProtector in $KeyProtectors){
    if($KeyProtector.KeyProtectorType -eq "RecoveryPassword"){
        try{
            # Remove then re-add the RecoveryPassword protector
            Remove-BitLockerKeyProtector -MountPoint $MountPoint -KeyProtectorId $KeyProtector.KeyProtectorId | Out-Null
            # Assuming BitLocker is configured properly, the recovery password will be stored in Active Directory, don't display it on screen
            Add-BitLockerKeyProtector -MountPoint $MountPoint -RecoveryPasswordProtector -WarningAction SilentlyContinue | Out-Null
            # If we get this far, eveything has worked, write a success to the event log
            Write-EventLog -LogName Application -Source $LogSource -EntryType Information -EventId 1000 -Message "BitLocker Recovery Password for $MountPoint has been changed"
            Write-Host "Successfully changed BitLocker Recover Password" -ForegroundColor Green
        }
        catch{
            # Something went wrong, display the error details and write an error to the event log
            $Error[0]
            Write-EventLog -LogName Application -Source $LogSource -EntryType Warning -EventId 1001 -Message "Failed to change Bitlocker Recovery Password for $MountPoint"
        }
    }
}
Posted in PowerShell, Security, Windows | Tagged , , , , , , , , , | 1 Comment

Get or update SysInternals tools with PowerShell

This is version 2 – the previous version relied on mapping a new PSDrive directly to \\live.sysinternals.com\tools which made things easy, but that no longer seems to work (or at least not for me, might be my web filtering blocking it).

So as an alternative, here is one that pulls the files directly via HTTPS by parsing the listing from http://live.sysinternals.com/tools

$SysIntFolder = "C:\sysint"
$Page = (Invoke-WebRequest -Uri "https://live.sysinternals.com/tools").Content
$MatchedItems = ([regex]"<A HREF.*?<\/A>").Matches($Page)
$ItemCount = $MatchedItems.Count
$Copied = 0
foreach($Match in $MatchedItems.Value){
    
    if($Match -match ">(.*?\..*?)<"){
        $Matches[1]
        Write-Progress -Activity "Update SysInt" -Status $Matches[1] -PercentComplete ($Copied / $ItemCount * 100)
        Invoke-WebRequest -Uri ("https://live.sysinternals.com/tools/" + $Matches[1]) -OutFile (Join-Path -Path $SysIntFolder -ChildPath $Matches[1])
    }
    $Copied++

}
Write-Progress -Activity "Update SysInt" -Completed
Posted in PowerShell, Windows | Tagged , , , , , , | Leave a comment

Network List Manager in PowerShell

I’m writing a network diagnostic script, and wanted to use the network status and connectivity information that’s already been captured by the Network List Manager (NLM).

The code for pulling various bits of info is below. NLM_Connectivity was a good opportunity to learn how to work with enumeration of flags, so I’ve included several examples of working with these, to both list all the active connectivity types, and also ways to check for a specific connectivity type.

$NetworkListManager = [Activator]::CreateInstance([Type]::GetTypeFromCLSID(‘DCB00C01-570F-4A9B-8D69-199FDBA5723B’))

# Set enums for GetNetworks
$NLM_ENUM_NETWORK_CONNECTED=1
$NLM_ENUM_NETWORK_DISCONNECTED=2
$NLM_ENUM_NETWORK_ALL=3

$Networks = $NetworkListManager.GetNetworks($NLM_ENUM_NETWORK_CONNECTED)

foreach($Network in $Networks){
# Network name
$Network.GetName()

# Values from INetworkListManager interface https://msdn.microsoft.com/en-us/library/windows/desktop/aa370769(v=vs.85).aspx

# Network category
$NetCategories = New-Object -TypeName System.Collections.Hashtable
$NetCategories.Add(0x00,"NLM_NETWORK_CATEGORY_PUBLIC")
$NetCategories.Add(0x01,"NLM_NETWORK_CATEGORY_PRIVATE")
$NetCategories.Add(0x02,"NLM_NETWORK_CATEGORY_DOMAIN_AUTHENTICATED")
$NetCategories.Get_Item($Network.GetCategory())

# Domain type
$DomainTypes = New-Object -TypeName System.Collections.Hashtable
$DomainTypes.Add(0x00,"NLM_DOMAIN_TYPE_NON_DOMAIN_NETWORK")
$DomainTypes.Add(0x01,"NLM_DOMAIN_TYPE_DOMAIN_NETWORK")
$DomainTypes.Add(0x02,"NLM_DOMAIN_TYPE_DOMAIN_AUTHENTICATED")
$DomainTypes.Get_Item($Network.GetDomainType())

# NLM Connectivity
$NLMConnectivity = New-Object -TypeName System.Collections.Hashtable
$NLMConnectivity.Add(0x0000,"NLM_CONNECTIVITY_DISCONNECTED")
$NLMConnectivity.Add(0x0001,"NLM_CONNECTIVITY_IPV4_NOTRAFFIC")
$NLMConnectivity.Add(0x0002,"NLM_CONNECTIVITY_IPV6_NOTRAFFIC")
$NLMConnectivity.Add(0x0010,"NLM_CONNECTIVITY_IPV4_SUBNET")
$NLMConnectivity.Add(0x0020,"NLM_CONNECTIVITY_IPV4_LOCALNETWORK")
$NLMConnectivity.Add(0x0040,"NLM_CONNECTIVITY_IPV4_INTERNET")
$NLMConnectivity.Add(0x0100,"NLM_CONNECTIVITY_IPV6_SUBNET")
$NLMConnectivity.Add(0x0200,"NLM_CONNECTIVITY_IPV6_LOCALNETWORK")
$NLMConnectivity.Add(0x0400,"NLM_CONNECTIVITY_IPV6_INTERNET")

# Several methods for working with the connectivity flags

# Display all active connectivity types (method a)
foreach($Key in $NLMConnectivity.Keys){
$KeyBand = $Key -band $net.GetConnectivity()
if($KeyBand -gt 0){
$NLMConnectivity.Get_Item($KeyBand)
}
}

# Display all active connectivity types (method b)
$NLMConnectivity.Keys | Where-Object {$_ -band $Network.GetConnectivity()} | ForEach-Object {$NLMConnectivity.Get_Item($_)}

# Display all active connectivity types (method c)
switch ($Network.GetConnectivity()){
{$_ -band 0x0000}{"NLM_CONNECTIVITY_DISCONNECTED"}
{$_ -band 0x0001}{"NLM_CONNECTIVITY_IPV4_NOTRAFFIC"}
{$_ -band 0x0002}{"NLM_CONNECTIVITY_IPV6_NOTRAFFIC"}
{$_ -band 0x0010}{"NLM_CONNECTIVITY_IPV4_SUBNET"}
{$_ -band 0x0020}{"NLM_CONNECTIVITY_IPV4_LOCALNETWORK"}
{$_ -band 0x0040}{"NLM_CONNECTIVITY_IPV4_INTERNET"}
{$_ -band 0x0100}{"NLM_CONNECTIVITY_IPV6_SUBNET"}
{$_ -band 0x0200}{"NLM_CONNECTIVITY_IPV6_LOCALNETWORK"}
{$_ -band 0x0400}{"NLM_CONNECTIVITY_IPV6_INTERNET"}
}

# Display all active connectivity types (method d)
Enum NLM_CONNECTIVITY {
NLM_CONNECTIVITY_DISCONNECTED = 0x0000
NLM_CONNECTIVITY_IPV4_NOTRAFFIC = 0x0001
NLM_CONNECTIVITY_IPV6_NOTRAFFIC = 0x0002
NLM_CONNECTIVITY_IPV4_SUBNET = 0x0010
NLM_CONNECTIVITY_IPV4_LOCALNETWORK = 0x0020
NLM_CONNECTIVITY_IPV4_INTERNET = 0x0040
NLM_CONNECTIVITY_IPV6_SUBNET = 0x0100
NLM_CONNECTIVITY_IPV6_LOCALNETWORK = 0x0200
NLM_CONNECTIVITY_IPV6_INTERNET = 0x0400
}
[enum]::GetValues([NLM_CONNECTIVITY]) | Where-Object {$_.value__ -band $Network.GetConnectivity()}

# Check for a particular type of connectivity (method a)
if(0x0040 -band $Network.GetConnectivity()){Write-Host "NLM_CONNECTIVITY_IPV4_INTERNET is active"}

# Check for a particular type of connectivity (method b)
$NLMConnectivityActiveFlags = $NLMConnectivity.Keys | Where-Object {$_ -band $Network.GetConnectivity()} | ForEach-Object {$NLMConnectivity.Get_Item($_)}
if($NLMConnectivityActiveFlags.Contains("NLM_CONNECTIVITY_IPV4_SUBNET")){Write-Host "NLM_CONNECTIVITY_IPV4_SUBNET is active"}
}

Posted in PowerShell | Tagged , , , , , , , , , | 1 Comment