Powershell: If You Want to Catch, Don't Forget to Throw

I made a Powershell scripting error the other day, and wanted to share my lesson learned.  In hindsight it seems obvious, but I made the mistake nevertheless, then cursed when my script presented with an apparent bug.

I had a script that iterated through a collection of items using a ForEach loop - an extremely common task in Powershell.  For each iteration of that ForEach loop, I performed a function that had a chance of failing, so I wrapped it in a Try/Catch block.  The rest of the ForEach loop below that performed further processing that depended on the success of the preceding function, so if the previous function failed, I wanted to skip the rest of that iteration and use the Continue statement to skip directly to the next ForEach iteration.

Let me illustrate:

:NextUser ForEach ($User In $Users)
{
    Try
    {
        Write-Debug "I'm about to try something risky..."
        Pre-Process $User
    }
    Catch
    {
        Write-Error $_.Exception        
        Continue NextUser
    }
    Write-Debug "Since pre-processing for $User was successful, I'm going to do more stuff here..."
    Post-Processing $User
}

And the Pre-Process function looked like this:

Function Pre-Process ($User)
{
    Try
    {
        [System.Some.Static]::Method($User)
    }
    Catch
    {
        Write-Error $_.Exception
    }
}

So what actually ended up happening was when the "Pre-Processing" function failed, it flashed an error message on the screen... but then the rest of the ForEach iteration continued to execute in an unpredictable and undesired way.  Why did my Continue statement in the Catch block not take me back to the next ForEach iteration?

Well as it turns out, the Catch block never ran.  Just because you catch an exception and use the Write-Error cmdlet doesn't mean you've thrown a terminating error to the caller.  And you need a terminating error in order to exit a Try block and go into a Catch block.  Since I was using a custom function, ErrorAction -Stop and $ErrorActionPreference didn't do anything for me. What I needed to do was use Throw to generate the needed terminating error.  What was throwing me off (no pun intended) was that I was confused as to which one of the Write-Error statements was actually taking place.  The one in the custom function, or the one in the ForEach loop that contained a call to the custom function?

In retrospect, I should probably stop using Try/Catch blocks altogether in custom Powershell functions.  You can easily suppress a needed exception with a Try/Catch and cause unintended bugs.

But for now, simply adding a Throw statement to my custom function was all I needed to activate the Catch block in the calling script:

Function Pre-Process ($User)
{
    Try
    {
        [System.Some.Static]::Method($User)
    }
    Catch
    {
        Write-Error $_.Exception
        Throw $_.Exception
    }
}

Be the Master of the LastLogonTimestamp Attribute with S4U2Self

I've written a little bit about the LastLogonTimestamp/LastLogonDate attribute here, and of course there is AskDS's notorious article on the subject here, but today I'm going to give you a handy little tip that I don't think I have mentioned before.

If you're an Active Directory administrator, chances are you're interested or have been interested in knowing if a given account is "stale," meaning that the account's owner has not logged in to the domain in some time.  (Keep in mind that an account could be either a user or a computer as it relates to Active Directory.)  You, like many sysadmins, might have some script or automated process that checks for stale accounts using a command-line approach, such as:

dsquery user -inactive 10

or Powershell's extremely flexible:

Get-ADUser -Filter * -Properties LastLogonDate
| ? { $_.Enabled -AND $_.LastLogonDate -LT (Get-Date).AddDays(-90) }

And then you take action on those inactive accounts, such as moving them to an "Inactive Users" OU, or disabling their accounts, or sending a reminder email to the account holder reminding them that they have an account in this domain, etc.

It might be handy for you to "artificially" update the lastLogonTimeStamp of another user though.  Maybe you know that this user is on vacation and you don't want their user account to get trashed by the "garbage collector" for being inactive.  According to the documentation, lastLogonTimeStamp is only editable by the system, so forget about directly modifying the attribute the way that you would other LDAP attributes.  And of course "LastLogonDate" is not a real attribute at all - merely a calculated attribute that Powershell gives you to be helpful by converting lastLogonTimestamp into a friendly .NET DateTime object.

The S4U2Self (Service for User to Self) Kerberos extension can help us here.

Just right click on any object such as an OU in Active Directory a folder in a file share, go to its Properties, then the Security tab.  Click the Advanced button.  Now go to the Effective Permissions tab.  Click the Select... button, and choose the user whose lastLogonTimestamp you want to update.  We are going to calculate the effective permissions of this inactive user:

By doing this, you are invoking the S4U2Self Kerberos extension, whereby the system will "go through the motions of Kerberos authentication and obtain a logon for the client, but without providing the client's credentials. Thus, you're not authenticating the client in this case, only making the rounds to collect the group security identifiers (SIDs) for the client."[1]

And just like that, you have updated the "Last Logon Time" on another user's behalf, without that user having to actually log on themselves.

Disable RC4-HMAC (And Others) in Active Directory

My long-distance pal Mathias Jessen pointed out this article today on Twitter, in which the article's author attempts to make us all shudder in fright at the idea that Microsoft Active Directory has a terrifying security vulnerability that will cause the world's corporate infrastructure to crumble and shatter humanity's socio-political status quo as script-kiddies take over the now destabilized Earth.

OK, it's not all that bad...

Of the several encryption types that AD supports for Kerberos authentication, RC4-HMAC is among the oldest and the weakest.  The reason the algorithm is still supported?  You guessed it... backwards compatibility.  The problem is that in this (perhaps ill-conceived, but hindsight's 20/20) implementation of RC4-HMAC, as outlined in RFC 4757, the encryption key that is used is the user's NT/MD4 hash itself!  What this means is that all I need is the NT hash of another user, and by forcing an AD domain controller to negotiate down to RC4-HMAC, I can be granted a Kerberos ticket as that other user.  (Getting another user's NT hash means I've probably already owned some random domain-joined workstation, for instance.)

As you probably already know, an NT hash is essentially password-equivalent and should be treated with the same level of sensitivity as the password itself.  And if you didn't know that, then you should read my earlier blog post where I talk a lot more about this stuff.

This was a deliberate design decision - that is, Microsoft is not going to just patch this away.  The reason they chose to do it this way was to ease the transition from NTLM to Kerberos back around the release of Windows 2000.  Newer versions of Windows such as Vista, 2008, 2008 R2, etc., use newer, better algorithms such as AES256_HMAC_SHA1 that do not use an NT hash.  Newer versions of Windows on a domain will automatically use these newer encryption types by default, but the older types such as the dreaded RC4-HMAC are still supported and can be used by down-level clients... or malicious users pretending to be down-level domain members.

As an administrator, you're free to turn the encryption type off entirely if you do not need the backwards compatibility.  Which you probably don't unless you're still rockin' some NT 4.0 servers or some other legacy application from the '90s.

(Which probably means most companies...)

Edit the Default Domain Controllers (or equivalent) Group Policy and look for the setting:

Computer Configuration > Policies > Windows Settings > Security Settings > Local Policies > Security Options > Network Security: Configure encryption types allowed for Kerberos.

This setting corresponds to the msDS-SupportedEncryptionTypes LDAP attribute on the domain controller computer objects in AD.  Enable the policy setting and uncheck the first three encryption types.

And of course, test in a lab first to ensure all your apps and equipment that uses AD authentication can deal with the new setting before applying it to production.

notdd v1.0

[Update: I renamed the program to be more unique.]

Hi again,

I started writing boot loaders in x86 assembly the other day, and I needed something that was capable of writing to the first sector of a storage device in order to test my creations.  I searched around the web, downloaded some old image burning software like it was 1999 all over again, and promptly got myself a malware/adware infection.  This pissed me right off, so after reinstalling my OS, I immediately set out to write my own.

notdd is what I came up with.


If you've ever wanted the complete, unbridled freedom of $&#%ing up your storage media on your own terms, then have I got the program for you!

And it also works for planting a custom boot sector on a disk.

Welcome to BlogEngine.NET 3.1

If you see this post it means that BlogEngine.NET is running and the hard part of creating your own blog is done. There is only a few things left to do.

Write Permissions

To be able to log in, write posts and customize blog, you need to enable write permissions on the App_Data and Custom folders. If your blog is hosted at a hosting provider, you can either log into your account’s admin page or call the support.

If you wish to use a database to store your blog data, we still encourage you to enable this write access for an images you may wish to store for your blog posts.  If you are interested in using Microsoft SQL Server, MySQL, SQL CE, or other databases, please see the BlogEngine docs to get started.

Security

When you've got write permissions set, you need to change the username and password. Find the sign-in link located either at the bottom or top of the page depending on your current theme and click it. Now enter "admin" in both the username and password fields and click the button. You will now see an admin menu appear. It has a link to the "Users" admin page. From there you can change password, create new users and set roles and permissions. Passwords are hashed by default so you better configure email in settings for password recovery to work or learn how to do it manually.

Configuration and Profile

Now that you have your blog secured, take a look through the settings and give your new blog a title.  BlogEngine.NET is set up to take full advantage of many semantic formats and technologies such as FOAF, SIOC and APML. It means that the content stored in your BlogEngine.NET installation will be fully portable and auto-discoverable.  Be sure to fill in your author profile to take better advantage of this.

Themes, Widgets & Extensions

One last thing to consider is customizing the look and behavior of your blog. We have themes, widgets and extensions available right out of the box. You can install more right from admin panel under Custom/Gallery.

On the web

You can find news about BlogEngine.NET on the official website. For tutorials, documentation, tips and tricks visit our docs site. The ongoing development of BlogEngine.NET can be followed at CodePlex where the daily builds will be published for anyone to download.

Good luck and happy writing.

The BlogEngine.NET team