• Sending out Password Expiration mails to users in Active Directory

    I was tasked with writing a script that would send out an e-mail to users, when there were 14,7,3,2 and 1 days before their AD passwords expired.

    I use the Quest AD cmdlets to get users from AD.



  • Troubleshooting Test-Connection

    I was contacted by a friend who was having some issues with Test-Connection  when using TimeToLive

    Example:

    Test-Connection -ComputerName www.google.ie -Count 1 -TimeToLive 3

    Test-Connection : Testing connection to computer ‘www.google.ie‘ failed: Problem with some part of the filterspec or providerspecific buffer in general

    At line:1 char:1

    + Test-Connection -ComputerName www.google.ie  -TimeToLive 3

    + ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

        + CategoryInfo          : ResourceUnavailable: (www.google.ie:String) [Test-Connection], PingException

        + FullyQualifiedErrorId : TestConnectionException,Microsoft.PowerShell.Commands.TestConnectionCommand

    So I fired fired up Reflector to see what Test-Connection actually does, and it is using WMI and the  Win32_PingStatus class, I have not been able to reproduce the error calling the class directly, so I was wondering where the problem could be.

    So I did a  trace command to see if that would give me anything, one thing I noticed in the return value there was a value called 11013, shortly thereafter this was written in the trace.

    MemberResolution Information: 0 :     "writeErrorStream" NOT present in type table.

    MemberResolution Information: 0 :     Adapted member: not found.

    This made me think that there might be an error in converting the Errorcode from its numerical value into text

    So I  looked up the errorcode from ICMP_ECHO_REPLY32 structure, which has an error code called 11013 which is:

    http://msdn.microsoft.com/en-us/library/windows/desktop/bb540657(v=vs.85).aspx

    IP_TTL_EXPIRED_TRANSIT
    11013

    The time to live (TTL) expired in transit.

    Which seems fair because TTL is relatively low, then I looked a bit deeper to try and find what 11013 also could mean

    In  Winsock Error Codes I found:

    http://msdn.microsoft.com/en-us/library/windows/desktop/bb540657(v=vs.85).aspx

    WSA_QOS_BAD_OBJECT
    11013
    QoS bad object.

    A problem was encountered with some part of the filterspec or the provider-specific buffer in general.

    Then I did some additional testing.

    PingPowerShell
    If you do a Trace-Command on the example with TimeToLive = 11 which gives the error: Error due to lack of ressources, you will see that the error code is 11010 which corresponds to:

    WSA_QOS_ADMISSION_FAILURE
    11010
    QoS admission error.

    A QoS error occurred due to lack of resources.

    If you look at the WMI Win32_PingStatus error codes 11010 corresponds to:

    IP_REQ_TIMED_OUT
    11010

    The request timed out.

    Which you can confirm using ping from the command prompt:

    PingDOS



  • The mystery of why Cisco AnyConnect stopped working

    A while back I tried to update my Intel Centrino Ultimate 6300 Wifi NIC to the latest drivers, to test Intel MY wifi while I was out travelling, but I never got it to work, it said it could not detect a suitable adaptor.. So I did not think more of that, until I had to connect to our corporate network, using Cisco AnyConnect, and I got through both primary and secondary authentication fine, but then the connection crapped out with “unable to establish vpn”.. So after a few reboots and troubleshooting I ended up uninstalling the new driver, and reverting back to the old Lenovo one, I was running before.

    Tonight I thought I would try again, to see if I could figure out what went wrong. So I installed the latest Intel drivers, and AnyConnect stopped working right away. So I went into Services to see what was “new” in there. I looked through all the Intel ones, and none of them looked “suspicious”, until I noticed that right below the Intel services, was “Internet Connnection Sharing (ICS)” and it was running. So I disabled it, and AnyConnected connected right away.

    So if you have trouble connecting with AnyConnect, see if your connection has ICS enabled, or if you do not need it at all, just disable the service.



  • Checking Site sizes in SharePoint 2007 and 2010

    Our Sharepoint admin asked me to help him write a script, that found out how much space each DocumentLibrary in our sharepoint farm took up, so after some googeling I found that I could use the StorageManagementInformation Method on the SPSite object, so I cam up with this little script

    [ps]
    #First we load the SharePoint assembly
    [void][System.Reflection.Assembly]::LoadWithPartialName("Microsoft.SharePoint")

    #Then we create a function that returns tje SPSite
    function Get-SPSite($url){
    return new-Object Microsoft.SharePoint.SPSite($url)
    }

    $site = Get-SPSite http://URL
    # We use the StorageManagementInformation Method on the $SPSite object, StorageManagementInformation returns a DataTable, and takes 4 input values
    # System.Data.DataTable StorageManagementInformation(Microsoft.SharePoint.SPSite+StorageManagementInformationType ltVar, Microsoft.SharePoint.SPSite+StorageManagementSortOrder sordVar, Microsoft.SharePoint.SPSite+StorageManagementSortedOn soVar, System.UInt32 nMaxResults)
    #
    # ltVar: What kind of storage management information to display
    # List = 1
    # DocumentLibrary = 2
    # Document = 3
    # sordVar: the direction in which the items are to be sorted
    # Increasing = 0×10
    # Decreasing = 0×11
    # soVar: whether the items are sorted by size or by date
    # Size=0
    # Date = 1
    # nMaxResults: the number of results to return

    $DT = $site.StorageManagementInformation(2,0×11,0,$(($site.allwebs).count));
    $DT | Select @{Label="Size"; Expression={[INT]($_.Size/1MB)}},Directory | out-gridview
    $site.Dispose()
    [/ps]

    Seems as if I forgot the last line, where I dispose of the Site object, I have added that now.



  • Updating .Htacces file based on Apache log files

    I am still seeing massive amounts of referal traffic hitting my site, eating up my bandwidth.. I did not get time to update my .htaccess file for the last 2 days.. and within the last 24 hours I have had more than 6000 hits, generating in almost 24.000 pageviews… Generating more than 1 GB worth of traffic (So at that speed I will reach my 10 GB limit soon)

    Looking through the Apache logs, figuring out which sites I get most referral traffic from, getting the hostnames, transforming them into a format that can be used by the Apache rewrite engine in the .htaccess file has been time consuming. So I decided that some powershell magic, might speed up the process a bit.

    [ps]
    function Select-FileDialog
    {
    param(
    [string]$Title,
    [string]$Directory,
    [string]$Filter="All Files (*.*)|*.*")
    [System.Reflection.Assembly]::LoadWithPartialName("System.Windows.Forms") | Out-Null
    $objForm = New-Object System.Windows.Forms.OpenFileDialog
    $objForm.InitialDirectory = $Directory
    $objForm.Filter = $Filter
    $objForm.Title = $Title
    $Show = $objForm.ShowDialog()
    If ($Show -eq "OK")
    {
    Return $objForm.FileName
    }
    Else
    {
    Write-Error "Operation cancelled by user."
    }
    }

    #Function to create the http rewrite rules.

    Function Create-Rewrite {
    Param (
    $Hostname
    )

    $HtaRule = "RewriteCond %{HTTP_REFERER} ^http://" + "$($hostname.replace(".","\."))" +" [OR]"
    $script:BlockList += $HtaRule
    }

    Function add-htaccess {
    Param (
    $HtaRules
    )
    (Get-Content $htaccess) | foreach-object {
    $_
    if ($_ -match "RewriteEngine") {
    if (!(Select-String -simplematch "$htarules" -Path $htaccess))
    {
    $HtaRules
    }
    }

    } | set-Content $tempFile
    Copy-Item $tempFile $htaccess
    }

    Function Upload-Ftp {
    Param ([Parameter(Position=0, Mandatory=$true)]
    [ValidateNotNullOrEmpty()]
    [System.String]
    $FTPHost,
    [Parameter(Position=1)]
    [ValidateNotNull()]
    $File
    )
    $webclient = New-Object System.Net.WebClient
    $uri = New-Object System.Uri($ftphost)

    "Uploading $File…"

    $webclient.UploadFile($uri, $File)
    }

    #Variables
    $log = Select-FileDialog -Title "Select an Apache logfile"
    $htaccess = "c:\Temp\.htaccess"
    $tempFile = [IO.Path]::GetTempFileName()
    $URLCount = 15
    $FTPUsername = "Username"
    $FTPPassword = "PassW0rd"

    $BlockList = ""
    #Create list of sites to block
    $script:BlockList = @()

    #Get the list of URLS in the the logfile, capturing each element into different named capturing groups

    $urls = Select-String ‘^(?<client>\S+)\s+(?<auth>\S+\s+\S+)\s+\[(?<datetime>[^]]+)\]\s+"(?:GET|POST|HEAD) (?<file>[^ ?"]+)\??(?<parameters>[^ ?"]+)? HTTP/[0-9.]+"\s+(?<status>[0-9]+)\s+(?<size>[-0-9]+)\s+"(?<referrer>[^"]*)"\s+"(?<useragent>[^"]*)"$’ $log |
    Select -Expand Matches | Foreach { $_.Groups["referrer"].value }

    #Output statistics for the referer hostnames (Only show top 15)
    $urls | group | ForEach -begin { $total = 0 }
    -process { $total += $_.Count; $_ } |Sort Count | Select Count, Name |
    Add-Member ScriptProperty Percent { "{0,15:0.00}%" -f (100*$this.Count/$Total) } -Passthru | select -Last $URLCount

    #Getting the base hostnames from the complete URLS, and outputs statistics to the screen.

    $hosts = $urls | Select-String '\b[a-z][a-z0-9+\-.]*://([a-z0-9\-._~%!$&()*+,;=]+@)?(?<host>[a-z0-9\-._~%]+|\[[a-z0-9\-._~%!$&()*+,;=:]+\])' |
    Select -Expand Matches | Foreach { $_.Groups["host"].value } | group | sort count | where {($_.name -notlike "*xipher.dk*") -and ($_.Count -gt 100)} |
    ForEach -begin { $total = 0 }

    -process { $total += $_.Count; $_ } | Sort Count | Select Count, Name |
    Add-Member ScriptProperty Percent { "{0,10:0.00}%" -f (100*$this.Count/$Total) } -Passthru

    Write-Host "List of root hostnames"

    $hosts

    Foreach ($Url in $hosts) {

    Create-Rewrite $url.Name
    }

    Foreach ($Block in $script:BlockList) {
    add-htaccess $Block
    }

    notepad $htaccess

    $script:BlockList

    Upload-Ftp -FTPHost "ftp://$($FTPUsername):$($FTPPassword)@xipher.dk/httpdocs/.htaccess" -File $htaccess
    Upload-Ftp -FTPHost "ftp://$($FTPUsername):$($FTPPassword)@xipher.dk/httpdocs/WordPress/.htaccess" -File $htaccess
    [/ps]

    Unfortunately my current hosting company, does not allow me to download the log files via FTP, but I have to connect to the Parallels interface and download it manually.. (I have not had the time looking into automating this part yet, so this is still a manual step)
    That is why I added a little function to use a GUI to pick the access_log file.

    [ps]
    function Select-FileDialog
    {
    param(
    [string]$Title,
    [string]$Directory,
    [string]$Filter="All Files (*.*)|*.*")
    [System.Reflection.Assembly]::LoadWithPartialName("System.Windows.Forms") | Out-Null
    $objForm = New-Object System.Windows.Forms.OpenFileDialog
    $objForm.InitialDirectory = $Directory
    $objForm.Filter = $Filter
    $objForm.Title = $Title
    $Show = $objForm.ShowDialog()
    If ($Show -eq "OK")
    {
    Return $objForm.FileName
    }
    Else
    {
    Write-Error "Operation cancelled by user."
    }
    }
    [/ps]

    I then call the function like this:

    [ps]
    $log = Select-FileDialog -Title "Select an Apache logfile"
    [/ps]

    A little Regex magic runs through the logfiles, and captures the different elements into different named capturing groups, in this step, I expand all referrer hostnames, and put them into the $urls variable

    [ps]
    $urls = Select-String ‘^(?<client>\S+)\s+(?<auth>\S+\s+\S+)\s+\[(?<datetime>[^]]+)\]\s+"(?:GET|POST|HEAD) (?<file>[^ ?"]+)\??(?<parameters>[^ ?"]+)? HTTP/[0-9.]+"\s+(?<status>[0-9]+)\s+(?<size>[-0-9]+)\s+"(?<referrer>[^"]*)"\s+"(?<useragent>[^"]*)"$’ $log |
    Select -Expand Matches | Foreach { $_.Groups["referrer"].value }
    [/ps]
    I modified a script by Joel Bennet, to get a little statistics as well, since there can be 1000’s of hostnames, I have selected only to output top 15 by default (using the $URLCount variable.

    [ps]
    $urls | group | ForEach -begin { $total = 0 }
    -process { $total += $_.Count; $_ } |Sort Count | Select Count, Name |
    Add-Member ScriptProperty Percent { "{0,15:0.00}%" -f (100*$this.Count/$Total) } -Passthru | select -Last $URLCount
    [/ps]

    Then I loop through all the hostnames, and extract the base domain name, using regex again. (Here I choose to ignore all traffic from my own domain name Xipher.dk, and I choose only to look for referral domains, that have generated 100 hits or more

    [ps]
    $hosts = $urls | Select-String '\b[a-z][a-z0-9+\-.]*://([a-z0-9\-._~%!$&()*+,;=]+@)?(?<host>[a-z0-9\-._~%]+|\[[a-z0-9\-._~%!$&()*+,;=:]+\])' |
    Select -Expand Matches | Foreach { $_.Groups["host"].value } | group | sort count | where {($_.name -notlike "*xipher.dk*") -and ($_.Count -gt 100)} |
    ForEach -begin { $total = 0 }

    -process { $total += $_.Count; $_ } | Sort Count | Select Count, Name |
    Add-Member ScriptProperty Percent { "{0,10:0.00}%" -f (100*$this.Count/$Total) } -Passthru
    [/ps]

    The script expects to find a .htaccess file in c:\temp containing at least the following two lines:

    RewriteEngine On
    RewriteRule (.*) http://%{REMOTE_ADDR}/$ [R=301,L]



  • Finally got confirmation.. Grown men do cry when their Bitlocker encrypted SSD disk dies ;(

    Had another visit from the ever present Mr Murphy, I have had a Lenovo T420 sitting on my desk for a while, as a replacement for my T410.. Finally last night I had some time to start moving over data to the new laptop. So I boot up both laptops, both have Windows Updates ready to install.. So I thought, I might as well, let it update, while I went out to get me something to drink. When I get back, my “old” laptop would’nt boot.. The SSD disk had suddenly stopped working. Even after 1 day at work, I have found that I have a lot of ad-hoc scripts, that I had not backed up… I am going on 7 weeks paternity leave next friday, so I had written a bunch of documentation, for my colleagues to have..

    So sorry to all those people I have made fun of over time, for having elaborate backup solutions for their laptops :)



  • Testing simple theme

    I am currently having some problems with my site, apparently it gets linked to be a lot of spam sites, resulting in more than 4000 visits in the last 24 hours. These “visitors” have generated over 1GB worth of traffic, and there is a 10GB cap on my current account.. So that this rate my site will be closed in 10 days :(



  • Fix 2008R2 scheduled tasks

    [ps]
    Function Change-ScheduledTask {
    Param($XMLIn)
    $ShortDate = [regex]"(?<shortdate>[0-9]{4}[/.-](?:1[0-2]|0[1-9])[/.-](?:3[01]|[12][0-9]|0[1-9])T(?:2[0-3]|[01][0-9])[:.][0-5][0-9][:.][0-5][0-9])(?<digits>\.\d*)"

    foreach ($line in $XMLIn){
    If ($line -match "$ShortDate") {
    $line = [regex]::Replace($line, $ShortDate, $($Matches["Shortdate"]))
    }
    $line
    #$Script:outfile += $line + "`n"
    }
    }

    Function Remove-ScheduledTask {

    }

    Function New-ScheduledTask {

    }

    $schtask = Schtasks.exe /query /s "localhost" /V /FO CSV | ConvertFrom-Csv

    if ($schtask) {

    Foreach ($sch in $schtask) {

    if ($Sch."Run As User" -like "$($domainname)*") {
    $sch
    }
    }

    $outfile = ""
    Change-scheduledtask $(Get-Content c:\temp\TestTask.xml)
    [/ps]



  • Send SMS through bibob with Powershell

    I thought I had posted this script more than a year ago, but apparently I have not. It is quite similar to the script, I posted recently sending SMS messages through unwire, this just allows bibob customers to send messages through bibobs online gateway.

    One thing to notice is that you are required to convert your password in an MD5 hash, before you send it. Here is a function to convert your plain passwords into an MD5 hash (Adapted from a script by Dennis Damen)

    [ps]
    Function New-MD5Hash {
    param(
    [Parameter(Position=0, Mandatory=$true)]
    [System.String]
    $inputString
    )
    $cryptoServiceProvider = [System.Security.Cryptography.MD5CryptoServiceProvider];
    $hashAlgorithm = new-object $cryptoServiceProvider
    $hashByteArray = $hashAlgorithm.ComputeHash($([Char[]]$inputString));
    foreach ($byte in $hashByteArray) { if ($byte -lt 16) {$result += “0{0:X}” -f $byte } else { $result += “{0:X}” -f $byte }}
    write-host $result
    }
    [/ps]
    Example of usage:

    Here is the bibob send sms script.
    [ps]
    <#
    .SYNOPSIS
    Send SMS through Bibob (Danish mobile phone company)

    .DESCRIPTION
    Send SMS Text messages through bibob SMS Gateway services

    .PARAMETER Content
    The text that the message should contain (Strings above 160 Chars will be split) [Mandatory]

    .PARAMETER Recipient
    The recipient phonenumber (8 digits) [Mandatory]

    .EXAMPLE
    PS C:\>Send-SMS -Content "Hello handsome" -Recipient 42424242

    .INPUTS
    System.String,System.Int32

    .OUTPUTS
    Sends SMS text message

    .NOTES

    .LINK
    about_functions_advanced

    .LINK
    about_comment_based_help

    #>

    function Send-SMS {
    [CmdletBinding()]
    param(
    [Parameter(Position=0, Mandatory=$true)]
    [System.String]
    $Content= "Hello Handsome",
    [Parameter(Position=1)]
    [System.Int32]
    $Recipient=42424242
    )
    begin {
    If ($Recipient -notmatch ‘^(\d{8})$’ )
    {Write-Host "Error in Phone Number"
    break
    }
    $Username = "42424242" # The same as your login to bibob.dk (You cannot spoof you sender number, so it is used as sender as well)
    $MD5Password = "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"

    }

    process {
    $objHTTP = New-Object -ComObject MSXML2.XMLHTTP
    $SoapServer = "https://www.bibob.dk/SmsSender.asmx"

    $XMLString = @"
    <?xml version="1.0" encoding="utf-8"?>
    <soap:Envelope xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/">
    <soap:Body>
    <SendMessage xmlns="http://www.bibob.dk/">
    <cellphone>$Username</cellphone>
    <password>$MD5Password</password>
    <smsTo>
    <string>$recipient</string>
    </smsTo>
    <smscontents>$content</smscontents>
    <fromNumber>$username</fromNumber>
    </SendMessage>
    </soap:Body>
    </soap:Envelope>
    "@

    $objHTTP.open(‘POST’, $SoapServer, $False)

    $objHTTP.setRequestHeader(‘Man’, ‘POST’ + ‘ ‘ + $SoapServer + ‘ HTTP/1.1′)
    $objHTTP.setRequestHeader(‘Host’, ‘www.bibob.dk’)
    $objHTTP.setRequestHeader(‘Content-Type’, ‘text/xml; charset=utf-8′)
    $objHTTP.setRequestHeader(‘Content-Length’, $($XMLString.Length))
    $objHTTP.setRequestHeader(‘SOAPAction’, ‘http://www.bibob.dk/SendMessage’)

    $objHTTP.send($XMLString)
    }
    }

    [/ps]