Wednesday, December 16, 2015

Tis the season for vacation clearing (and password expiration)

As we approach the end of the year, along with its holidays, its common for many employees to take leave for long periods of time.  So as a gift to helpdesks everywhere, often they would request to know who will have their password expire during the peak holiday times (to prepare for the support calls).  To build a list like this is quite easy with powershell.  This assumes you don't have fine grain password policies.  In this example, we look at expiring passwords between Dec 21 and Jan 4 given the working days and anticipated return dates around the Christmas and New Years holidays:

import-module activedirectory

#grab the domain wide password policy and extract a # of days integer
$passwordage = (Get-ADDefaultDomainPasswordPolicy).MaxPasswordAge |select -exp days

#define your start and end filter dates and subtract the max Password age value.
#We need to calculate using passwordlastset timestamps

$startdate = ([datetime]"12-21-2015").adddays(-$passwordage)
$enddate = ([datetime]"1-4-2016").adddays(-$passwordage)

#Filter as much as possible on the LDAP side with the date ranges.
#The Select statement includes a calculated
#expression to convert the passwordlastset value to an actual expiration date.
#Convert to CSV and output to file.
#Zip it and mail it out.

get-aduser -filter {(enabled -eq $true) -and (passwordlastset -ge $startdate) -and (passwordlastset -le $enddate)} -Properties passwordlastset, mail | select samaccountname, name, mail, @{name="ExpirationDate"; exp={$_.passwordlastset.adddays($passwordage)}} | convertto-csv -notypeinfo | out-file .\expiringholidays.csv

Tuesday, December 15, 2015

Checking Mcafee DAT version information remotely with powershell

This script can be used to remotely check a Mcafee client's datversion number and the date of the DAT file's release. It uses basic remote registry reading techniques, so remote registry access (usually administrator on the remote machine) will be required for it to work. You can use this script as a template for other registry reading operations that you may need. It is a basic script that only accepts single computer input. You can change parameters and turn this into a function to handle pipeline or array input.

Update July 2018. Added a secondary registry key in due to some differences I'm seeing in my environment lately. With different product versions and EPO use, this location may move around a bit. If you find this code doesn't work for you, check the current dat version in the taskbar icon, then search the registry for the dat version number. This should get you to the location that your product is storing this information in.


param (
 [parameter(mandatory=$true)][string]$computername
)
function ping-host([string]$computername) {
 #This function will perform a simple, small size single packet ping of a machine and return true/false for the result
  if ([string]::IsNullOrEmpty($computername) ) {return $false}
  #ping first for reachability check
  $po = New-Object net.NetworkInformation.PingOptions
  $po.set_ttl(64)
  $po.set_dontfragment($true)
  [Byte[]] $pingbytes = (65,72,79,89)
  $ping = new-object Net.NetworkInformation.Ping
  $savedEA = $Erroractionpreference
  $ErrorActionPreference = "silentlycontinue"
  $pingres = $ping.send($computername, 1000, $pingbytes, $po)
  if (-not $?) {return $false}
  $ErrorActionPreference = $savedEA
  if ($pingres.status -eq "Success") { return $true } else {return $false}
}


if ((ping-host $computername) -eq $false) {
 New-Object PSobject -Property @{
  Computername = $computername
  DATVersion = "System Not Online"
  Datdate = $null
 }
} else {

 try {
  #Set up the key that needs to be accessed and what registry tree it is under
  $key = "Software\McAfee\AVEngine"
  $type = [Microsoft.Win32.RegistryHive]::LocalMachine

  #open up the registry on the remote machine and read out the TOE related registry values
  $regkey = [Microsoft.win32.registrykey]::OpenRemoteBaseKey($type,$computername)
  $regkey = $regkey.opensubkey($key)
  $status = $regkey.getvalue("AVDatVersion")
  $datdate = $regkey.getvalue("AVDatDate")
 } catch {
  try {
   $key = "Software\Wow6432Node\McAfee\AVEngine"
   $type = [Microsoft.Win32.RegistryHive]::LocalMachine
   #open up the registry on the remote machine and read out the TOE related registry values
   $regkey = [Microsoft.win32.registrykey]::OpenRemoteBaseKey($type,$computername)
   $regkey = $regkey.opensubkey($key)
   $status = $regkey.getvalue("AVDatVersion")
   $datdate = $regkey.getvalue("AVDatDate")
  } catch {
     #try newer registry location
    try {
     $key = "Software\Wow5432Node\Network Associates\ePolicy Orchestrator\Application Plugins\VIRUSCAN880"
     $regkey = [Microsoft.win32.registrykey]::OpenRemoteBaseKey($type,$computername)
     $regkey = $regkey.opensubkey($key)
     $status = $regkey.getvalue("DATVersion")
     $datdate = $regkey.getvalue("DatDate")
    } catch {
      $status = "Cannot read regkey"
    }
  }
 }
 New-Object PSobject -Property @{
  Computername = $computername
  DATVersion = $status
  DatDate = $datdate
 } |select Computername,DatVersion,DatDate
}

Thursday, December 3, 2015

Powershell Switch for a numeric range

There are several ways of handling a range of values in a Switch statement in powershell. In this example, I will show a simple conversion of a numeric month value to a quarter [string].

First example:
switch($month){
 {1..3 -contains $_}{"Q1"}
 {4..6 -contains $_}{"Q2"}
 {7..9 -contains $_}{"Q3"}
 {10..12 -contains $_}{"Q4"}
 
}


The range operator returns an array of the numbers in that specified range, so we use -contains to test our value. If we left out -contains, all switch values would match as no comparison is being made, yet the range is being evaluated as true.

Second example:
switch($month) {
 {$_ -le 3} {"Q1";break;}
 {$_ -le 6} {"Q2";break;}
 {$_ -le 9} {"Q3";break;}
 {$_ -le 12} {"Q4"; break;}
}


The key to this example is the Break statement. Without this, everything would match as the switch operator continues to evaluate for all possible matches (not just the first one). Break will cause it to stop evaluating.

Third example:

switch($month) {
 {$_ -ge 1 -and $_ -le 3} {"Q1"}
 {$_ -ge 4 -and $_ -le 6} {"Q2"}
 {$_ -ge 7 -and $_ -le 9} {"Q3"}
 {$_ -ge 10 -and $_ -le 12} {"Q4"}

}


The more "wordy" example with multiple conditions and the -And. This may be more readable, however the first example does a pretty good job with this. The functionality is far more obvious than example #2. In any case, using conditions to check a range of values will save time and code. Alternatively (though not very elegant or practical), you can use a regex switch for this:

switch -regex ([string]$month) {
 "^[1-3]$" {"Q1"}
 "^[4-6]$" {"Q2"}
 "^[7-9]$" {"Q3"}
 "^1[0-2]$" {"Q4"}
}