PS > Get-Traffic – a quick look at parsing HTML with Powershell

The norwegian equivalent of the DMV, Statens Vegvesen, have a website where they publish real time traffic information collected from the electronic toll payment tags that most cars are fitted with here near Oslo.

Here’s how it looks right now at noon – no congestion at all:Conegestion

Let me translate the important parts:
Reisetid uten forsinkelse: 12 min
(Travelling time without delays: 12 min)
Forsinkelse: 1 min
(Delay: 1 min)
Forventet reisetid nå: 13 min
(Expected travelling time now: 13 min)

This is what the script will output:

PS > Get-Traffic
This looks OK, maybe it's time to leave?

Current : 13
Normal : 12
Delay : 0
DelayFactor : 1,08333333333333
Route : Skøyen - Asker

 

And here’s the script:

function Get-Traffic
{
    [cmdletbinding()]
    Param(
        [int]$ID,
        [int]$DelayThreshold = 1.5
    )


    if(-not($ID))
    {
        Write-Verbose "No route ID was defined"
        if ((get-date).hour -in 6..12)
        {
            $ID = "1039"
        }
        else
        {
            $ID = "1040"
        }
        Write-Verbose "Route ID is $($ID)"
    }
    
    $URL = "http://www.reisetider.no/reisetid/strekning.html?method=trafikkinformasjon&id=$ID"
    $Response = Invoke-WebRequest $URL
    $ExpectedTravellingTime = (($Response.ParsedHtml.body.innerText) -split ":" | select -Last 1) -replace " min",""
    $NormalTravellingTime = (((($Response.ParsedHtml.body.innerText) -split "`r`n")[0]) -split ":")[1] -replace " min",""
    $Delay = $ExpectedTravellingTime - $NormalTravellingTime
    $Route = ((((Invoke-WebRequest "http://www.reisetider.no/reisetid/strekning.html?id=$ID").ParsedHtml.getElementsByTagName("span")) | Where-Object className -eq "brodsmulemeny-valgt").innertext)

        
    $Traffic = [pscustomobject]@{
        "Current"     = $ExpectedTravellingTime 
        "Normal"      = $NormalTravellingTime
        "Delay"       = $Delay
        "DelayFactor" = ($ExpectedTravellingTime / $NormalTravellingTime)
        "Route"       = $Route
    }

    if ($Traffic.Delayfactor -ge $DelayThreshold)
    {
        Write-Output "Too much traffic, go back to work!"
        Write-Output $Traffic
    }
    else
    {
        Write-Output "This looks OK, maybe it's time to leave?"
        Write-Output $Traffic
    }
}

As you can see, pretty easy stuff. Parsing the HTML requires some trial and error, but with the help of Chrome Developer Tools, this took no more than 2 minutes.

Advertisements

PS > Export-BitlockerRecoveryKeys

This script exports all Bitlocker recovery information for all computer objects in your domain. Run it as a scheduled task – but make sure to set appropriate permissions on the resulting CSV file!

function Export-BitlockerRecoveryKeys
{
    [CmdletBinding()]
    Param
    (
        $CSVFile = "c:\scripts\BitlockerExport.csv",
        $Computers = (Get-ADComputer -Filter *)
    )

    Begin
    {
        if(-not(Test-Path $CSVFile))
        {
            $null = New-Item -Path $CSVFile -Force -Type File
        }

        $Array = @()
        $CurrentData = Import-Csv $CSVFile -ErrorAction SilentlyContinue
    }

    Process
    {
        foreach ($Computer in $Computers)
        {
            $RecoveryKey = Get-ADObject -SearchBase $Computer.DistinguishedName -Filter {objectClass -eq 'msFVE-RecoveryInformation'} -Properties msFVE-RecoveryPassword
            if($RecoveryKey)
            {
                foreach ($Key in $RecoveryKey)
                {
                    if($CurrentData.key -notcontains $Key.'msFVE-RecoveryPassword')
                    {
                        $ThisComputer = [pscustomobject]@{
                            "Name" = $computer.name
                            "Date" = ($key.Name -split "{")[0] -as [datetime]
                            "ID"   = ($key.Name -split "{")[1].TrimEnd("}")
                            "Key"  = $key.'msFVE-RecoveryPassword'
                        }
                        $Array += $ThisComputer
                    }
                }
            }
        }
    }

    End
    {
        $Array | Export-Csv -Path $CSVFile -Append

        if ($Array.Count -ne 0)
        {
            Write-Verbose "Exported $($Array.count) new keys!"
        }
        else
        {
            Write-Verbose "No new keys"
        }
    }
}

Running this script daily on a DC is a simple way of keeping an extra backup of all your keys. Just remember to treat the list the same way you treat your domain admin password: with care!

PS > Add-DirectAccessClient

DirectAccess deployments on Windows Server 2012++ requires clients to be members of a predefined security group. I wanted to automate adding computers to this group. Run this script as a scheduled task every x minutes, and let the problem solve itself!

function Add-DirectAccessClient
{
    [CmdletBinding()]
    Param
    (
        $DirectAccessGroup   = (Get-ADGroup -Identity "DirectAccess"), #Gets the DistinguishedName of your DirectAccess security group.
        $DirectAccessMembers = ($DirectAccessGroup | Get-ADGroupMember | select -ExpandProperty name), #Stores a list of all computer names currently added to your DirectAccess security group
        $SearchBaseOU        = (Get-ADComputer -Properties MemberOf -SearchBase "OU=Laptops,OU=Computers,OU=Division,DC=Company,DC=com") #Point this towards your Computer OU
    )

    Begin
    {
        try
        {
            $null = Get-Module ActiveDirectory -ErrorAction Stop
        }
        catch
        {
            Write-Error -Message "Module ActiveDirectory was not found. Install RSAT, or run the script on a DC/Remote PS Session"
        }
    }

    Process
    {
        foreach ($Computer in $SearchBaseOU)
        {
            if($Computer.Name -notin $DirectAccessMembers)
            {
                try
                {
                    Add-ADGroupMember -Identity $DirectAccessGroup -Members $Computer.DistinguishedName -ErrorAction Stop
                    Write-Output "Added: $($Computer.Name)"
                }
                catch
                {
                    Write-Error -Message "Unable to add computer to group. Missing permissions?"
                }
            }
        }
    }
}