PowerShell HTML Color Temperature Scale

The following function is a representation of a formula I’ve worked on-and-off with for the past several years.  I often like to represent a value with a “common” temperature gradient which goes gradually from blue through green and yellow to eventually red.  In short, something like this:

TemperatureScale

Or, representing percent in steps of 10 as an example:

0 10 20 30 40 50 60 70 80 90 100

As it would turn out, this isn’t as simple as it first seems.  Ultimately, I ended up with the following 3 distinct gradient calculations (values going from 0-255)

First third: starting with a blue RGB of 64,128,255, gradually increase Green and reduce Blue.
Second third: gradually increase Red, keep Green steady, and phase out Blue.
Third third: gradually phase out Green, leaving just Red.

I’ve written 3 functions in the following code section.  The first one returns an object with the separate RGB components; the second returns the hex code value; the third is a quick way of generating a reference bar (such as the two I’ve included above).

Function TemperatureColor([double]$percent)
{
    [int]$weight=($percent/100.0)*768.0
    $color=New-Object PSObject -Property @{Red=255;Green=255;Blue=255}
    if($weight -ge 768) { $Color.Red=255; $Color.Green=0; $Color.Blue=0 }
    elseif($Weight -ge 512) { $Color.Red=255; $Color.Green=768-$weight; $Color.Blue=0 }
    elseif($Weight -ge 256) { $Color.Red=($weight-256)*0.75+64; $Color.Green=255; $Color.Blue=255-($weight/2) }
    elseif($Weight -ge 0)   { $Color.Red=64; $Color.Green=128+($weight/2); $Color.Blue=255-($weight/2) }
    else { $Color.Red=255; $Color.Green=255; $Color.Blue=255 }
    $Color.Red=[int]$Color.Red
    $Color.Green=[int]$Color.Green
    $Color.Blue=[int]$Color.Blue
    $Color
}

Function HexColor($Percent)
{
$Color=TemperatureColor($Percent)
    "{0:x2}{1:x2}{2:x2}" -f $Color.Red,$Color.Green,$Color.Blue
}

Function TemperatureScaleTable {
[CmdletBinding()]
Param(
    [Parameter(Mandatory=$false,Position=0)][double]$Step=5,
    [Parameter(Mandatory=$false,Position=1)][Switch]$Reverse=$false,
    [Parameter(Mandatory=$false,Position=2)][Switch]$NoValue,
    [Parameter(Mandatory=$false,Position=3)][Switch]$NoBorder,
    [Parameter(Mandatory=$false,Position=4)][int]$CellWidth=5
)
    if($NoBorder)
    {
        $html="<TABLE style=""border: 0px; border-collapse: collapse;"">"
    } else {
        $html="<TABLE>"
    }
    $html+="<TR style=""height: 20px"">"

    For($i=0;$i -le 100; $i+=$step)
    {
        $v=$i
        $width=""
        if($Reverse) { $v=100-$i }
        if($NoValue) { $v=" ";$width="width: $($CellWidth)px" }
        $html+="<td style=""background-color: #$(HexColor($i)); $width"">$v</td>"
    }
    $html+="</TR></TABLE>"
    $html | Out-String
}

The two bars above were generated with the following code:

TemperatureScaleTable -Step 1 -CellWidth 1 -NoValue -NoBorder
TemperatureScaleTable -Step 10

The parameters for TemperatureScaleTable let you change the number of values and even reverses those values (if you want 100=blue and 0=red).

In my next post, I’ll show you how to make use of this function to create a color-coded disk volume report that quickly shows you your “hot spots” where you may be low on disk space.

Posted in Uncategorized | Leave a comment

Whose password is expiring soon?

A recent effort at work has a large number of users who do not log into the domain on which their Exchange mailbox resides. As a result, they don’t get the Windows warnings when their password is about to expire.

The effort required isn’t all that hard, once you find the right property!

The following script returns, by default, all passwords that will be expiring within the next 7 days (the number of days is a parameter)… it wouldn’t take much to modify this to additionally send a gentle reminder email to the affected people that their password is about to expire.

[CmdletBinding()]
Param(
    [Parameter(Mandatory=$false,Position=0,ValueFromPipeline=$true)]$domain="contoso.com",
    [Parameter(Mandatory=$false,Position=1,ValueFromPipeline=$true)][alias("OU")]$OrganizationalUnit="OU=Users,DC=Contoso,DC=com",
    [Parameter(Mandatory=$false,Position=2,ValueFromPipeline=$true)][int]$Days=7

)

$adu=Get-ADUser -Server $Domain -SearchBase $OrganizationalUnit -Filter * -Properties msDS-UserPasswordExpiryTimeComputed,DisplayName,Mail
$exp=$adu | Select Name,DisplayName,Mail,@{Name="Password Expiration";Expression={[datetime]::FromFileTime($_.'msDS-UserPasswordExpiryTimeComputed')}}
$exp | % { if( $_.'Password Expiration' -gt (Get-Date) -and ($_.'Password Expiration' - (Get-Date)).Days -le $Days) { $_ } }

Not bad for just a few lines of code!

Posted in Uncategorized | Leave a comment

Exchange Outlook Mobile App detection

I had an opportunity where I needed to discover everyone using the “new” Outlook Web App available from iTunes or Google Play.

In case you didn’t know, these applications show up as registered mobile devices, just like an ActiveSync device.  The differentiating factor is that their ClientType property is MOWA instead of the usual EAS designator.

Combine this with a -filter command, and recognizing that, from an identity parameter perspective, the parent of all mobile devices is the actual user (and therefore the parent of the parent of the device is the user), a few short lines will populate a variable with the unique mailboxes which have a MOWA-registered device:

Set-ADServerSettings -ViewEntireForest $True
$mowa=Get-MobileDevice -Filter { ClientType -eq 'MOWA' } -ResultSize Unlimited
$mowaDNs=$mowa | % { $_.Identity.Parent.Parent } | Select -Unique
$mowaMBs=$mowaDNs | Get-Mailbox -ResultSize Unlimited

That’s it! Now your $mowaMBs contains all users who have a registered device!

Posted in Uncategorized | Leave a comment

PowerShell and Image Meta information (even RAW)

Several years ago I developed a DOS Batch script that would make double-copies of images off flash media (for loss protection) and then file them to specific directories based on Year-Month-Day as well as prepending the camera model* to the file to ensure the filenames were unique.  I was thinking of converting to PowerShell since there is a lot more capability there than Ye Olde DOS prompt.

First step, how do I get Meta data information from a raw camera file into PowerShell?

Well, a little reading and experimentation, and it becomes a rather short one-liner.  This example uses the file 5D_IMG_9027.CR2 and assumes ExifTool is installed in the local directory:

$meta=([xml](.\exiftool.exe .\5D_IMG_9027.CR2 -X)).rdf.description

Here’s an example of some of the attributes after processing:

PS C:\pics> $meta=([xml](.\exiftool.exe .\5D_IMG_9027.CR2 -X)).rdf.description
PS C:\pics> $meta | fl ISO,CanonModel,Lens,Aperture,ShutterSpeed

ISO          : {100, 100, 100}
CanonModel   : 5D
Lens         : 85.0 mm
Aperture     : 1.8
ShutterSpeed : 1/25

Now that is pretty awesome!

Note: If you’re looking to do this for a large number of files, I recommend using ExifTool’s batch mode and doing the conversion from XML once, instead of once for each file.

*This is actually accomplished with a bit of ExifTool programming… place this file in the same directory and it “exposes” a new variable called CanonModel:

#
# .ExifTool_config
#
%Image::ExifTool::UserDefined = (
    'Image::ExifTool::Composite' => {
        CanonModel => {
            Require => {
                0 => 'Model',
            },
            ValueConv => 'length($val[0]) > 4 ? substr($val[0], rindex($val[0]," ")+1, 100) : undef',
        },
    },
);

P.S. If you’re looking for less information than what ExifTool can provide, you can look into “new-object -com shell.application” or “[System.Windows.Media.Imaging.BitmapFrame]” but neither of those had the detail nor capability on CR2 or other raw files.

Posted in Uncategorized | Leave a comment

Powershell Find Unique and/or Duplicate entries

Yesterday I had a case where a co-worker was trying to determine how many licenses for a particular package were in use.  Unfortunately, users are spread across multiple independent systems, but from a licensing perspective, we only need to could each individual once.

The source files were in CSV format, and each contained a column called “name”.  Some of them had additional columns, but they were ignored in this particular example.

 

$UserList1=Import-Csv UserList1.CSV
$UserList2=Import-Csv UserList2.CSV

$names=@()

$UserList1 | % { $names += $_.name }
$UserList2 | % { $names += $_.name }

# At this point $names contains all the names from both files

write-output "Total names: " ($names | measure).count
Total names:
5052
write-output "Unique names: " ($names | group | measure).count
Unique names:
4922

In order to interpret the results, lets look at what those last couple lines do.

write-output "Total names: " ($names | measure).count

This line takes the list of names, passes it through Measure-Object, and retrieves the .count property, so it’s a total count.

write-output "Unique names: " ($names | group | measure).count

This line takes the list of names, groups them by common name, and then counts how many groups.  Since each duplicate becomes a single row now, this is your unique count.  Since the difference is 130, that means 130 “accounts” show up 2 or more times.  The “real” unique license count is 4922.

Taking this one step further, who are your duplicates?  One more line gives a nice output (actual names deleted)

PS C:\temp\notes> $names | group | where-object { $_.count -gt 1 } | ft Count,Name -autosize

Count Name
----- ----
    2 B***** , L*****
    4 B***** , S***
    2 B***** , L*****
    2 C*** , H**
    3 J**** , M***

As you can see, here the output shows how many accounts each individual shows up!

P.S. I leave it up the the reader to change if they want the output sorted by Count or Name.

Posted in Uncategorized | Leave a comment

Active Directory Thumbnail Images

Part of the new functionality in Exchange is the capability of adding a (very small) thumbnail image.  A side benefit of this is that it will show up as the “Default Corporate Image” for Lync, which was the impetus of why I was looking at this in the first place!

Enter an old program I used to use a lot: ImageMagick (www.imagemagick.org)

The trick with these thumbnail images is that the recommended size is 96×96 pixels.  But if you just take any photograph and resize it to 96×96, it will most likely be above the size limit you can upload, which is a paltry 10 kb.

Here’s an easy one that will convert most images to below that, and still retain more than enough quality:

convert source-image.jpg -resize 96x96 -quality 85 -strip target-image.jpg

converts to

Deceptively simple, but very efficient.  It changes the quality of the image but not enough that it is really visible.  -strip simply removes all the extras which get added (EXIF information, for instance).

After that, pull up your EMS and do:

Import-RecipientDataProperty -identity target-account -Picture -FileData ([Byte[]] $(Get-Content -Path target-image.jpg -Encoding Byte -ReadCount 0))

Congratulations – you’ve just updated your Active Directory thumbnailPhoto attribute!

Posted in Uncategorized | Leave a comment