Learned something new about PowerShell forms today

I’ve been working on a form app using PowerShell. This particular app provides an initialization form window fooled by the main window.

I had already run across that the initialization form would not run if I used the standard ShowDialog method since PowerShell forms run one per console. The solution was to use the Show method for the initialization form window.

That led to my next discovery : a label object (System.Windows.Forms.Label) will not display properly if the Show method is used to display the form. Instead all that appears is a white box. The solution was to use a textbox object instead.

~~~~~~~~~~~~~~~~~~~~~

UPDATE : I found that if the Refresh method is used on the label it will show as it should.

Comments Off on Learned something new about PowerShell forms today Posted in PowerShell

Testing a password meets complexity using PowerShell

A small bit of code to check if a password meets the Windows AD complexity rules. The only thing this does not do is check to see if the password being treated contains the username.

$pw2test = “{Enter some password to test here}”
$isGood = 0
If (-Not($pw2test -notmatch “[a-zA-Z0-9]”)) #check for special chars
     { $isGood++ }
If ($pw2test -match “[0-9]”)
     { $isGood++ }
If ($pw2test -cmatch “[a-z]”)
     { $isGood++ }
If ($pw2test -cmatch “[A-Z]”)
     { $isGood++ }
If ($isGood -ge 3)
     { $pw2test + ” is a good password” | Out-Default }
Else
     { $pw2test + ” is not a good password” | Out-Default }

Comments Off on Testing a password meets complexity using PowerShell Posted in PowerShell

Spam sucks

Today I found an email from Diane Schultz ( diane@franchise-path.com ) which was quite obviously a form email trying to get me to buy into a franchising scheme. The really odd post was it was on an email address I exclusively use for job searches. And it was done using a spamming outfit called Stream Send ( http://www.streamsend.com ).  Stream Send lists among its partners and affiliates the DMA, which means that they probably follow the same harvest-spam-make-them-opt-out misbehavior of other DMA partners.

To both of them – thank you for wasting my time with junk there was no reason to think I would be interested in.

Unlocking an account on every DC without forcing replication

Today I’m going to go over a script which will address an issue admins in a large network face : unlocking an account on DCs that spread across multiple WAN links WITHOUT FORCING A REPLICATION.

This script is fairly straight forward but does require the person running it have domain admin privileges and access to the AD PowerShell extensions.

The core of what is needed is a simple command : Unlock-ADAccount. We can start by laying out that command:

Unlock-ADAccount <user>

Since we are interested in doing this on all DCs we’ll include the option -Server. Obviously we can do it the hard way:

Unlock-ADAccount <user> -Server DC1
Unlock-ADAccount <user> -Server DC2
….

But that is hard work if you have a lot of DCs, say 50 or more, or if the DCs are changing. So let’s add something to the script to make it smarter:

$DCList = Get-ADComputer -Filter * -SearchBase ‘ou=Domain Controllers,dc=contoso,dc=com’
Foreach ($targetDC in $DCList.Name)
{
Unlock-ADAccount <user> -Server $targetDC
}

We’ve added a little brains here. The Get-ADComputer cmdlet is used to get the names of all the computers [-Filter *] in our Domain Controllers OU [-SearchBase ‘ou=Domain Controllers,dc=contoso,dc=com’]. We’re dumping the results of this command into the variable $DCList. The end result is that we wind up with an array where each item in the array has multiple properties. We’re interested in one, Name. The Foreach command essentially allows us to loop through all of the array values one at a time. We use another single-value variable, $targetDC, to hold the current DC name. In five lines we are able to do what might take a hundred or more.

So far so good. But what happens if a DC is offline or unreachable? The script blows up. We’ll add an option to our Unlock-ADAccount cmdlet to keep everything going along rather than just halting

$DCList = Get-ADComputer -Filter * -SearchBase ‘ou=Domain Controllers,dc=contoso,dc=com’
Foreach ($targetDC in $DCList.Name)
{
Unlock-ADAccount <user> -Server $targetDC -ErrorAction SilentlyContinue
}

Now the script will just roll on if it hits a downed DC. But it would be nice to know about that, right? So let’s add TRY-CATCH

$DCList = Get-ADComputer -Filter * -SearchBase ‘ou=Domain Controllers,dc=contoso,dc=com’
Foreach ($targetDC in $DCList.Name)
{
Try
{
Unlock-ADAccount <user> -Server $targetDC -ErrorAction SilentlyContinue
}
Catch
{
$errormsg = $targetDC + ” is down/not responding.”
Write-Host $errormsg -ForegroundColor white -BackgroundColor red
}
}

There. Now we get a message indicating a particular DC was down. The ForegroundColor option allows us to specify white as the text color, while the BackgroundColor option allows us to specify red as the text background, making it stand out in our shell window.

But if we’re doing that why not give ourselves a clue as to where we’re at by doing something similar in the Try section:

$DCList = Get-ADComputer -Filter * -SearchBase ‘ou=Domain Controllers,dc=contoso,dc=com’
Foreach ($targetDC in $DCList.Name)
{
Try
{
Unlock-ADAccount <user> -Server $targetDC -ErrorAction SilentlyContinue
Write-Host (“Completed on ” + $targetDC) -BackgroundColor DarkGreen
}
Catch
{
$errormsg = $targetDC + ” is down/not responding.”
Write-Host $errormsg -ForegroundColor white -BackgroundColor red
}
}

Great, but it’s kind of useless to have to adjust the script for each user. Let’s add an argument to our script and, before trying the script, check to make sure it isn’t empty.

$targetacct = $args[0]
if ($targetacct -ne $null)
{
$DClist = get-adcomputer -filter * -SearchBase ‘ou=domain controllers,dc=contoso,dc=com’ | Sort-Object name
Try
{
Get-ADUser $targetacct
Foreach ($targetDC in $DClist.Name)
{
“Processing ” + $targetacct + ” on DC ” + $targetDC | Out-Default
Try
{
Unlock-ADAccount $targetacct -Server $targetDC -ErrorAction SilentlyContinue | Out-Null
Write-Host (“Completed on ” + $targetDC) -BackgroundColor DarkGreen
}
Catch
{
$errormsg = $targetDC + ” is down/not responding.”
Write-Host $errormsg -ForegroundColor white -BackgroundColor Red
}
}
}
Catch
{
$errormsg = $targetacct + ” is an INVALID account. Check to see if it exists and that this is the SAM name.”
Write-Host $errormsg -ForegroundColor white -BackgroundColor Red
}
}
else
{
write-host “INVALID Parameters!”
Write-Host “USAGE: unlock.ps1 <USERNAME>”
}

Not only have we added the input from arguments (the first line), but in the second line we set up an IF-ELSE structure to ensure we have an actual value. [And yell at us when we don’t!] We also added an additional line [“Processing….”] so that we have an even better idea of what is being tried, not just whether it succeeded or not. There’s even a check [Try … Get-ADUser….] to see if the account actually exists and exit if it doesn’t.

Granted this is a linear script and can several minutes to run based on WAN links and DC load, but that is a lot better that forcing a replication across multiple small pipes.

Comments Off on Unlocking an account on every DC without forcing replication Posted in Uncategorized