Thursday, February 12, 2015

Use Google Sheets cell content in script


Wouldn't it be nice to collect data using a Google Sheets Form and be able to get each cell value from a script on your phone or computer? It can be done.

I'm assuming the data you need for your script is already in a Google Sheet. It could be collected using a form or similar. To get unauthenticated access to a Google Sheet it needs to be published. Either publish the sheet containing the data or create a and publish new Google Sheet to hold only the data needed for the script. Import the data to that new sheet using =IMPORTRANGE().

To get the URL for the published sheet, have a look at this page: https://developers.google.com/gdata/samples/spreadsheet_sample. Basically you just need the key for the sheet.

The published sheet URL looks something like this:

Cell C2 would look like this:

OK, on to the content. Below is the content I get when requesting cell R1C1. The actual data is between the tags <content type='text'> and </content>

<?xml version='1.0' encoding='UTF-8'?><entry xmlns='http://www.w3.org/2005/Atom' xmlns:batch='http://schemas.google.com/gdata/batch' xmlns:gs='http://schemas.google.com/spreadsheets/2006'><id>https://spreadsheets.google.com/feeds/cells/<key>/od6/public/basic/R1C1</id><updated>2014-12-12T07:35:19.026Z</updated><category scheme='http://schemas.google.com/spreadsheets/2006' term='http://schemas.google.com/spreadsheets/2006#cell'/><title type='text'>A1</title><content type='text'>2</content><link rel='self' type='application/atom+xml' href='https://spreadsheets.google.com/feeds/cells/<key>/od6/public/basic/R1C1'/></entry>

We just need to split the content on <content type='text'> and then split the second part again on </content>. The cell data is in the first part of the second split.

PowerShell example:
$CellA1 = Invoke-WebRequest -UseBasicParsing -Uri https://spreadsheets.google.com/feeds/cells/1DzK0hnq9bexu6h1ryZzPP6-WWk55IEx0xZrtFKK6UZI/od6/public/basic/R1C1
$Value = (($CellA1 -split "<content type=.text.>") -split "</content")[1]
Tasker example:
GetValueFromSheet (4)
A1: HTTP Get [ Server:Port:https://spreadsheets.google.com/ Path:feeds/cells/<key>/od6/public/basic/R1C1 Attributes: Cookies: User Agent: Timeout:10 Mime Type: Output File: Trust Any Certificate:Off ] 
A2: Variable Split [ Name:%HTTPD Splitter:<content type='text'> Delete Base:On ] 
A3: Variable Split [ Name:%HTTPD2 Splitter:</content> Delete Base:On ] 
A4: Variable Set [ Name:%Value To:%HTTPD21 Do Maths:Off Append:Off ] 
The content of A1 in the Google Sheet is now in Tasker variable %Value. You could use this to trigger other Tasker tasks or to present that value on a Zooper Widget, or send it to Pushover. I use it for a few things, and might write a more detailed end-to-end post on that.

Wednesday, February 11, 2015

Change Exchange primary email address to lower case

By default Microsoft Exchange creates email addresses on the form First.Last@domain.com. If you change the email address policy to use lowercase, the existing email addresses are not updated to reflect that change.

It doesn't work to change the primary SMTP address to lower case right away, since email addresses are basically case insensitive. When you set a new primary SMTP address, the old address is kept as an alias email address. Exchange can't set a new primary email address since the same address already exists as an alias. More or less, you get the picture.

I created the following script to make the change


# Get all mailboxes in the users OU (select the OU for which you want to change to lower case
$Mailboxes = Get-Mailbox -OrganizationalUnit "OU=Users,DC=domain,DC=com" -ResultSize Unlimited
# Loop through all mailboxes
ForEach ($Mailbox in $Mailboxes)
{
    # Turn off email address policy
    Set-Mailbox -Identity $Mailbox.Identity -EmailAddressPolicyEnabled $false
    # Set a temporary primary email address
    Set-Mailbox -Identity $Mailbox.Identity -PrimarySmtpAddress "dummy@domain.com"
    # Remove the old primary address which is now a standard email address connected to the mailbox
    Set-Mailbox -Identity $Mailbox.Identity -EmailAddresses @{Remove=$Mailbox.PrimarySmtpAddress}
    # Convert the old primary address to lowercase
    $lowercasesmtp = $Mailbox.PrimarySmtpAddress.ToLower()
    # Set the lowercase email address as primary
    Set-Mailbox -Identity $Mailbox.Identity -PrimarySmtpAddress $lowercasesmtp
    # Remove the temp primary address
    Set-Mailbox -Identity $Mailbox.Identity -EmailAddresses @{Remove='dummy@domain.com'}
    # Turn on the address policy
    Set-Mailbox -Identity $Mailbox.Identity -EmailAddressPolicyEnabled $true
    # Check the result
    Get-Mailbox -Identity $Mailbox.Identity | select Name, *SMTP*, Email*
}

Wednesday, January 21, 2015

Exchange 2013 mailbox quota usage and size report

In Exchange 2013 it can be a bit hard to find mailboxes that are close to their quota limits. You can see it in the Exchange Admin Center, but that is a tedious task if you want to check all mailboxes.
You can also wait for the users to contact you when they get a quota warning, or when they no longer can send email. That's a bit late.
With PowerShell you can easily find out the mailbox size, but the quota limit is either Unlimited, which means that the mailbox database defaults are used, or it can be set at a certain limit.

Find the mailbox quota
get-mailbox mailbox | select-object DisplayName, ProhibitSendQuota, ProhibitSendReceiveQuota

DisplayName ProhibitSendQuota ProhibitSendReceiveQuota
----------- ----------------- ------------------------
User Name   Unlimited         Unlimited

Find the mailbox size and database quota
Get-MailboxStatistics -identity mailbox | select-object Displayname,TotalItemSize,TotalDeletedItemSize,DatabaseIssueWarningQuota,DatabaseProhibitSendQuota

DisplayName               : User Name
TotalItemSize             : 1.125 GB (1,208,281,527 bytes)
TotalDeletedItemSize      : 24.14 MB (25,309,210 bytes)
DatabaseIssueWarningQuota : 5 GB (5,368,709,120 bytes)
DatabaseProhibitSendQuota : 6 GB (6,442,450,944 bytes)


So, the numbers are all there, just not in a nice format...

To make a long story short - here's a PowerShell script that will output all mailboxes with a quota usage over 80%

<#
.SYNOPSIS
    TGet-MailboxSizeQuota.ps1 returns all mailboxes above a certain quota (ProhibitSendQuota) usage.
.DESCRIPTION
    TGet-MailboxSizeQuota.ps1 returns all mailboxes with a quota usage of 80% and above.
    If you want to check for another quota limit, pass the percentage as a parameter.

    TGet-MailboxSizeQuota.ps1 
.EXAMPLE
    TGet-MailboxSizeQuota.ps1
    The above command will return all mailboxes with a quota usage of 80% and above
.EXAMPLE
    TGet-MailboxSizeQuota.ps1 85
    The above command will return all mailboxes with a quota usage of 85% and above
.NOTES
    Author: Peter Haake
    Date:   2015-01-20    
#>
#
# Load the Exchange Management Module
Add-PSSnapin Microsoft.Exchange.Management.PowerShell.SnapIn
# Make sure en-us locale is used no matter what the server/user has configured
# Keep this section if you output decimal numbers
# Slightly modified from From http://occasionalutility.blogspot.com.au/2014/03/everyday-powershell-part-17-using-new.html
[System.Reflection.Assembly]::LoadWithPartialName("System.Threading")>$null
[System.Reflection.Assembly]::LoadWithPartialName("System.Globalization")>$null
[System.Threading.Thread]::CurrentThread.CurrentCulture = [System.Globalization.CultureInfo]::CreateSpecificCulture("en-us")

# Set quotalimit to the first parameter passed. If no parameter is passed, set it at 80%
if ([INT]$args[0] -gt "") {
    $quotalimit = [INT]$args[0]
    }
else {
    $quotalimit = 80
}

# Get all mailboxes
$Mailboxes = @(Get-Mailbox -ResultSize Unlimited | select-object DisplayName, Identity, ProhibitSendQuota, ProhibitSendReceiveQuota)
# Clear the report object variable
$Report =@()

# Loop through all mailboxes
foreach ($usr_mailbox in $Mailboxes)
{
    # Get statistics for all mailboxes
    $usr_mailboxstats = Get-MailboxStatistics -identity $usr_mailbox.Identity | select-object Displayname,Identity,Database,TotalItemSize,TotalDeletedItemSize,DatabaseIssueWarningQuota,DatabaseProhibitSendQuota

    #Convert TotalItemSize to INT64 and remove crap (looks like this initially "1.123 GB (1,205,513,370 bytes)" and comes out as a numeric 1205513370)
    [int64]$usr_mailboxstats_totalitemsize = [convert]::ToInt64(((($usr_mailboxstats.TotalItemSize.ToString().split("(")[-1]).split(")")[0]).split(" ")[0]-replace '[,]',''))
    #Convert TotalDeletedItemSize to INT and remove crap (looks like this initially "1.123 GB (1,205,513,370 bytes)" and comes out as a numeric 1205513370)
    [int64]$usr_mailboxstats_totaldeleteditemsize = [convert]::ToInt64(((($usr_mailboxstats.TotalDeletedItemSize.ToString().split("(")[-1]).split(")")[0]).split(" ")[0]-replace '[,]',''))

    # If the mailbox quota is Unlimited, then the database defaults are used.
    if ($usr_mailbox.ProhibitSendQuota -eq "Unlimited") {
        # Get quota from Database
        [INT64]$usr_quota = [convert]::ToInt64(((($usr_mailboxstats.DatabaseProhibitSendQuota.ToString().split("(")[-1]).split(")")[0]).split(" ")[0]-replace '[,]',''))
        }
    else {
        # Get quota from user mailbox
        [INT64]$usr_quota = [convert]::ToInt64(((($usr_mailbox.ProhibitSendQuota.ToString().split("(")[-1]).split(")")[0]).split(" ")[0]-replace '[,]',''))
    }
    # Calculate the quota percentage
    $usr_quota_percentage = [INT]((($usr_mailboxstats_totalitemsize + $usr_mailboxstats_totaldeleteditemsize) / $usr_quota)*100)

    # Add to report object
    if ($usr_quota_percentage -ge $quotalimit) {
        $usr_reportObject = New-Object PSObject
        $usr_reportObject | Add-Member -MemberType NoteProperty -Name "DisplayName" -Value $usr_mailboxstats.DisplayName
        $usr_reportObject | Add-Member -MemberType NoteProperty -Name "TotalItemSize" -Value $usr_mailboxstats_totalitemsize
        $usr_reportObject | Add-Member -MemberType NoteProperty -Name "TotalDeletedItemSize" -Value $usr_mailboxstats_totaldeleteditemsize
        $usr_reportObject | Add-Member -MemberType NoteProperty -Name "ProhibitSendQuota" -Value $usr_quota
        $usr_reportObject | Add-Member -MemberType NoteProperty -Name "QuotaPercent" -Value $usr_quota_percentage
        $report += $usr_reportObject
    }
}
# Output the report, sorted with the highest quota percentage at the top
$Report | Sort-Object QuotaPercent -Descending

 Output looks something like this

DisplayName  TotalItemSize  TotalDeletedItemSize  ProhibitSendQuota  QuotaPercent
-----------  -------------  --------------------  -----------------  ------------
User Name       8316860830              49373170         9663676416            87
Second User    14581624515              17277483        17179869184            85
Third Person    5472939739              15151742         6442450944            85

Send the output from the script as an email

If you want to schedule the script to run every week or so, it might be convenient to have the output sent to you in an email. Create another script, and call TGet-MailboxSizeQuota.ps1 from that as below:

Send-MailMessage -to email@domain.com -Subject "Quota Report" -SmtpServer mail.server.FQDN -From from@domain.com -Body (C:\Scripts\TGet-MailboxSizeQuota.ps1 | ft | Out-String)

This can easily be added as a scheduled task. Just make sure to run the task under a user account that has enough rights in Exchange.