# encoding: ascii
# api: powershell
# title: GPRS Online log
# description: Scan the System Event log for all GPRS online activity – PCMCIA, USB, mobile phone, etc. A Balloon Tip will also be issued when the SIM card is about to expire (Needs an icon file to be named ‘exclamation.ico’ for this feature to work).
# version: 0.1
# type: script
# author: Archdeacon
# license: CC0
# x-poshcode-id: 1469
# x-archived: 2009-11-13T08:19:14
#
#
################################################################################
# Get-GprsTime.ps1(V 1008)
#       Check the total connect time of any GPRS devices from a specified date. 
# Use the -Verbose switch for some extra information if desired. A default value
# can be set with the -Monthly switch but can be temporarily overridden with any
# -Start value and deleted by entering an invalid date.  Now uses .NET Parse to 
# use any culture date input. Switches -M and -S cannot be used together.
#       A Balloon prompt will be issued in the Notification area for the 5 days
# before the nominal month end, and a suitable Icon (exclamation.ico) file needs 
# to be available in the $PWD directory for this to work.
# NOTE:  this can effectively be suppressed by using a value higher than the SIM
# card term, ie something like -Account 90 for a 30 day card which will override 
# the default setting. Use -Today to check only today's usage.
# Use 'Set-Alias Get-GprsTime -Account 30' to set value permanently to 30 days.
# Examples:
#    .\Get-GprsTime.ps1 -Monthly 4/8/2009
#    .\Get-GprsTime.ps1 -Start 12/07/2009 -Account 100 -Verbose
#    .\Get-GprsTime.ps1 -m 5/9/2009
#    .\Get-GprsTime.ps1  10/4/2009 -v
#    .\Get-GprsTime.ps1 -v
#    .\Get-GprsTime.ps1 -Today
#    .\Get-GprsTime.ps1
#
# The author can be contacted at www.SeaStarDevelopment.Bravehost.com and the
# 'exclamation.ico' file is included in the Gprs100x.zip download there.
################################################################################
Param ([String] $start,
       [String] $monthly,
       [Int]    $account = 0,     #Start warning prompt 5 days before month end.
       [Switch] $today,
       [Switch] $verbose,
	   [Switch] $debug)
 
Trap [System.Management.Automation.MethodInvocationException] {
    [Int]$line = $error[0].InvocationInfo.ScriptLineNumber
	[System.Media.SystemSounds]::Hand.Play()
    If ($line -eq  165) {
	    Write-Warning "[$name] Current GPRS variable has been deleted."
	    $monthly = ""
	    [Environment]::SetEnvironmentVariable("GPRS",$monthly,"User")
    }
	Else {
		Write-Warning "[$name] Date is missing or invalid $SCRIPT:form"
	}
    Exit 1
}

$name = $myInvocation.MyCommand
$newLine = "[$name] The switches -Start and -Monthly can only be used separately."
If ($debug) {
	$DebugPreference = 'Continue'
}
If ($start -and $monthly) {
    [System.Media.SystemSounds]::Hand.Play()
    Write-Warning "$newLine"
    Exit 1
}
$SCRIPT:form = ""

#In certain cases Culture & UICulture can be different and have been known to
# return conflicting results regarding '-is [DateTime]' queries, etc.
If ($Host.CurrentCulture -eq $Host.CurrentUICulture) {
    $SCRIPT:form = '-Use format mm/dd/year'               
    [Int]$culture = "{0:%d}" -f [DateTime] "6/5/2009"        #Returns local day.
    If ($culture -eq 6) {
		$SCRIPT:form = '-Use format dd/mm/year'
    }
}
$ErrorActionPreference = 'SilentlyContinue'
$VerbosePreference = 'SilentlyContinue'
$WarningPreference = 'Continue'
$conn = $disc = $default = $print = $null              
$timeNow = [DateTime]::Now 
$total = $timeNow - $timeNow                     #Set initial value to 00:00:00.
$insert = "since"
If ($verbose) {
    $VerbosePreference = 'Continue'
}

Function CreditMsg ($value, $value2) {
    $value = [Math]::Abs($value)
    $prefix = "CURRENT"
    [DateTime] $creditDT = $value2 
	$creditDT = $creditDT.AddDays($value)                #Add the -Account days.
	$thisDay = "{0:M/d/yyyy}" -f [DateTime]::Now               #Force US format.
	#If we use '$number = $creditDT - (Get-Date)' instead of the line below we
	#can sometimes get a value of 1 returned instead 2, hence the  above  lines.
	$number = $creditDT - [DateTime] $thisDay
	[String] $credit = $creditDT   
	$credit = $credit.Replace('00:00:00','')          #Remove any trailing time.
	$credit = "{0:d}" -f [DateTime]$credit
	Switch($number.Days) {
            1            {$prefix = "($value days) will expire tomorrow"; break}
            0            {$prefix = "($value days) will expire today"; break}
            -1           {$prefix = "($value days) expired yesterday"; break}
            {($_ -lt 0)} {$prefix = "($value days) expired on $credit"; break}
            {($_ -le 5)} {$prefix = "($value days) will expire on $credit"}
            Default      {$prefix = "CURRENT"}   #Only come here if over 5 days.
	}
    Return $prefix
}

Function Interval ([String] $value) {
    Switch($value) {
   		{ $_ -match '^00:00:\d+(.*)$' } {$suffix = "seconds"; break}
		{ $_ -match '^00:\d+:\d+(.*)$'} {$suffix = "minutes"; break}
		Default                         {$suffix = "  hours"}
    }
    Return $suffix
}

Function CheckSetting ($value) {
	If ($value) {
		$print = $default.ToShortDateString()        #Correct for local culture.
	}
	Else {
		$print = "(Value not set)"
	}
	Return $print
}
#The Script effectively starts here.............................................
$getGprs = [Environment]::GetEnvironmentVariable("GPRS","User")
#First check for GPRS variable and change from US date format to current locale.
If ([DateTime]::TryParse($getGprs, [Ref]$timeNow)) { #No error as date is valid.
	$default = "{0:d}" -f [datetime]$getGprs 
	$default = [DateTime]::Parse($default)  
	$checkYear = "{0:yyyy}" -f $default
	$checkMonth = "{0:%M}" -f $default
	$dayCount = [DateTime]::DaysInMonth($checkYear,$checkMonth)    #Range 28-31.
	If($account -eq 0) {
		$account = $dayCount
		$summary = "$($dayCount.ToString()) days" 
	}
	Else {
		$summary = "$($account.Tostring()) days"
	}
	$text = CreditMsg $account $getGprs  #Check if within 5 days of expiry date.
	If (($text -ne "CURRENT") -and (Test-Path "$pwd\exclamation.ico") ) {
    	[void] [System.Reflection.Assembly]::LoadWithPartialName("System.Windows.Forms")
    	$objNotifyIcon = New-Object System.Windows.Forms.NotifyIcon 
    	$objNotifyIcon.Icon = "$pwd\exclamation.ico" 
    	$objNotifyIcon.BalloonTipIcon  = "Info" 
    	$objNotifyIcon.BalloonTipTitle = "GPRS online account"
    	$objNotifyIcon.BalloonTipText  = "Credit $text"
    	$objNotifyIcon.Visible = $True 
    	$objNotifyIcon.ShowBalloonTip(10000)
	}
}
Else {
	$summary = "(Days not set)"
	If ((!$today) -and (!$monthly) -and (!$start)) {
		[System.Media.SystemSounds]::Hand.Play()
		Write-Warning("Monthly date is either invalid or not set.")
		Exit 1
	}
}
If ($start) {
    $start = [DateTime]::Parse($start)                 #Trigger TRAP if invalid!
	[DateTime]$limit = $start
    $convert = "{0:D}" -f $limit
	$print = CheckSetting $default
} 

If ($monthly) {
    $start = [DateTime]::Parse($monthly)               #Trigger TRAP if invalid!
	Write-Output "Setting GPRS (monthly) environment variable to: $monthly"
    $gprs = [String]$start.Replace('00:00:00','')
    [Environment]::SetEnvironmentVariable("GPRS",$gprs,"User")
    [DateTime] $limit = $start               #Change to required US date format.
    $convert = "{0:D}" -f $limit
	$print = $limit.ToShortDateString()
	$summary = "(Days undetermined)"                #Will show next time around.
}

If ($today) {                    
    $verBosePreference = 'Continue'                    #Show VERBOSE by default.
    [DateTime] $limit = (Get-Date)
    $convert = "{0:D}" -f $limit
    $limit = $limit.Date         #Override any start date if using -Today input.
    $insert = "for today"
	$print = CheckSetting $default
}
If ((!$today) -and (!$monthly) -and (!$start)) {        
	If ($default) {
    	$monthly = $default
		[DateTime] $limit = $monthly
		$convert = "{0:D}" -f $limit
		$print = CheckSetting $default
	}
}
Write-Verbose "All records $($insert.Replace('for ','')) - $convert"
Write-Verbose "Script activation - User [$($env:UserName)] Computer [$($env:ComputerName)]"
Write-Output ""
Write-Output "Calculating total connect time of all GPRS modem devices..."
                    #We cannot proceed beyond here without a valid $limit value.
Write-Debug "Using - [Search date] $($limit.ToShortDateString()) [Account] $summary [GPRS Monthly] $print"					

$lines = Get-EventLog system | Where-Object {($_.TimeGenerated -ge $limit) -and `
    ($_.EventID -eq 20159 -or $_.EventID -eq 20158)} 
If ($lines) {
    Write-Verbose "A total of $([Math]::Truncate($lines.Count/2)) online sessions extracted from the System Event Log."
}
Else {
    Write-Output "(There are no events indicated in the System Event Log)"
}
$lines | ForEach-Object {
    $source = $_.Source
    If ($_.EventID -eq 20159) {                      #Event 20159 is Disconnect.
       $disc = $_.TimeGenerated
    } 
    Else {                                              #Event 20158 is Connect.
       $conn = $_.TimeGenerated	
    }                  #We are only interested in matching pairs of DISC/CONN...
    If ($disc -ne $null -and $conn -ne $null -and $disc -gt $conn) {
       $diff = $disc - $conn
       $total += $diff
       $convDisc = "{0:G}" -f $disc
       $convConn = "{0:G}" -f $conn
       $period = Interval $diff
       Write-Verbose "Disconnect at $convDisc. Online - $diff $period"
       Write-Verbose "   Connect at $convConn."
    }
}   #End ForEach
If (!$source) {
    $source = '(Undetermined)'
}
Write-Verbose "Using local event source - System Event Log [$source]"
$period = Interval $total
Write-Output "Total online usage $insert $convert is $total $($period.Trim())."
Write-Output ""
