Tuesday, September 27, 2011

PowerShell ActiveDirectory Module vs Quest.ActiveRoles.ADManagement Snapin

I have used the Quest.ActiveRoles.ADManagement snapin for a few years and have enjoyed their ease of use. Now that we have migrated our domain controllers to 2008 R2, I often use the ActiveDirectory Module. In fact, I end up using both and see no reason to pick one over the other.

Being of curious nature, I wanted to compare the time it took for a standard query to run using both approaches. Following is a comparison of:
  • Quest.ActiveRoles.ADManagement snapin with Where-Object
  • Quest.ActiveRoles.ADManagement snapin with LDAP Filter
  • ActiveDirectory Module with Filter parameter
  • ActiveDirectory Module with LDAP Filter
The query is looking for "stale" servers and runs 10 times for each one and averages the result.

# Add required snapin and module    
Add-PSSnapin Quest.ActiveRoles.ADManagement -ErrorAction SilentlyContinue
Import-Module ActiveDirectory -ErrorAction SilentlyContinue

$d = ((Get-Date).AddDays(-90)).ToFileTime()
$LDAP = "(&(OperatingSystem=*Server*)(pwdLastSet<=$d)(!(userAccountControl:1.2.840.113556.1.4.803:=2)))"
$server = "DC-P01"

# Quest.ActiveRoles.ADManagement with Where-Object
$QAD_Where = (1..10 | foreach {
(Measure-Command -Expression {
Get-QADComputer -Service DC-P01 -OSName '*Server*' -PasswordNotChangedFor 90 `
| Where-Object {-not $_.AccountIsDisabled}}).TotalSeconds
} | Measure-Object -Average
).Average

# Quest.ActiveRoles.ADManagement with LDAP filter
$QAD_LDAP = (1..10 | foreach {
(Measure-Command -Expression {
Get-QADComputer -Service $server -LDAPFilter $LDAP }).TotalSeconds
} | Measure-Object -Average
).Average

# Active Directory Module with Filter parameter
$AD_Filter = (1..10 | foreach {
(Measure-Command -Expression {
Get-ADComputer -Server $server -Filter { (OperatingSystem -like "*Server*") -AND
(PasswordLastSet -le $d) -AND (Enabled -eq $True)}}).TotalSeconds
} | Measure-Object -Average
).Average

# Active Directory Module with LDAP Filter
$AD_LDAP = (1..10 | foreach {
(Measure-Command -Expression {
Get-ADComputer -Server $server -LDAPFilter $LDAP}).TotalSeconds
} | Measure-Object -Average
).Average

"Quest.ActiveRoles.ADManagement with Where-Object took {0:N2} seconds." -f $QAD_Where
"Quest.ActiveRoles.ADManagement with LDAPFilter took {0:N2} seconds." -f $QAD_LDAP
"Active Directory Module with filter took {0:N2} seconds." -f $AD_Filter
"Active Directory Module with LDAPFilter took {0:N2} seconds." -f $AD_LDAP

The results (for the most part) are not surprising.
Quest.ActiveRoles.ADManagement with Where-Object took 4.97 seconds.
Quest.ActiveRoles.ADManagement with LDAPFilter took 4.19 seconds.
Active Directory Module with filter took 3.20 seconds.
Active Directory Module with LDAPFilter took 3.21 seconds.

At some point, I need to run this again with a long running query.

Is this consistent with your results?

Enjoy!

Monday, August 29, 2011

PowerShell and Benford's Law

Was reading through a statistics blog (R) the other day when I read a posting on Benford's law. The definition according to the blog is:

"
Benford's law, also called the first-digit law, states that in lists of numbers from many (but not all) real-life sources of data, the leading digit is distributed in a specific, non-uniform way. According to this law, the first digit is 1 about 30% of the time, and larger digits occur as the leading digit with lower and lower frequency, to the point where 9 as a first digit occurs less than 5% of the time."

The probabilities are distributed as demonstration here.



This seemed counter-intuitive and I wanted to validate it myself. Let's look at the leading digit of all the txt files in one of my directories. Enter PowerShell.....
# Explore Benford's Law 

$array=@()
foreach ($item in (Get-ChildItem -Path p:\ -Filter *.txt -Recurse))
{
$array+= $item.length.toString()[0]
}

$array `
| Group-Object -NoElement `
| Sort-Object count -Descending `
| Format-Table @{label=”#”;expression={$_.Name}},
@{label=”Count”;expression={"{0:%##}" -f $($_.Count/$array.Count)}},
@{label=”Histogram”;expression={“▄” * $_.Count}} -autosize

I consider this a validation, but lets try one another example, this time looking at leading digits on the workingset of the processes on my desktop:

$array=@()       

foreach($a in (Get-Process))
{
$array+= $a.WorkingSet.toString()[0]
}

$array `
| Group-Object -NoElement `
| Sort-Object count -Descending `
| Format-Table @{label=”#”;expression={$_.Name}},
@{label=”Count”;expression={"{0:%##}" -f $($_.Count/$array.Count)}},
@{label=”Histogram”;expression={“▄” * $_.Count}} -autosize

Again, this seems to hold true. Now that I have examples of Benford's law, I feel compelled to try and understand it. Wish me luck!


Thursday, August 25, 2011

Setting user LogonWorkstations and LogonHours in Active Directory

​If you find the need to add restrictions to a user in Active Directory, specifically LogonWorkstations and logonHours then the following script will serve as a template.

A few notes:
- We are using the ActiveDirectory module
- We are using a set list of workstations
- We are using a template approach for the logon hours

Import-Module ActiveDirectory -ErrorAction SilentlyContinue  


# Define the list of workstations we want to allow access
$WorkStations = "Workstation1,Workstation2,Workstation3"
$WorkStations+= "Workstation4,Workstation5,Workstation6"
$WorkStations+= "Workstation7,Workstation8,Workstation9"

# Create the logonHours array
[array]$logonHours = (Get-ADUser test010 -Properties logonHours).logonHours

# Iterate over users and assign accordingly
foreach ($user in Get-Content C:\temp\users.txt) {
Get-ADUser -Identity $user |
`
Set-ADUser -LogonWorkstations $Workstations -Add @{logonhours=$logonHours}
}
Checking our results shows that the logonHours were set exactly to what our template was.


Enjoy!

Thursday, June 23, 2011

Printer exploration with PowerShell

Following are a few printing related PowerShell one-liners that I demonstrated for a few colleagues at work. -Enjoy!
# List all printer drivers on a specific server           
Get-WmiObject -Class Win32_PrinterDriver -ComputerName PrintServer `
| Sort-Object Name `
| Select-Object Name, DriverPath

# List all properties of a specifc printer driver on a server
Get-WmiObject Win32_PrinterDriver -ComputerName PrintServer -Filter "Name='Lexmark Universal XL,3,Windows x64'"

# List Printers for a specific server
Get-WmiObject Win32_Printer -ComputerName PrintServer `
| Sort-Object Name `
| Select-Object Name, DriverName, PortName, ShareName

# List a specific printer on a server
Get-WmiObject Win32_Printer -ComputerName PrintServer -Filter "Name='P-UHC6000M-IRC2550'"

# List info on print jobs
Get-WmiObject Win32_PrintJob -ComputerName PrintServer `
| Select-Object Document, Owner,
@{Label="Status";Expression={$_.JobStatus}},
@{Label="PageCount";Expression={$_.TotalPages}},
@{Label="DateSubmitted";Expression={[System.Management.ManagementDateTimeconverter]::ToDateTime($_.TimeSubmitted)}}

# List current number of jobs in each print queue
Get-WmiObject -Class Win32_PerfFormattedData_Spooler_PrintQueue -Computer PrintServer -Filter "Name <> '_Total' and Jobs > 0" `
| Sort Jobs -Descending `
| Select name, jobs `
| Format-Table -AutoSize

Saturday, February 5, 2011

PowerShell doesn't cure insomnia

Had a bit of trouble sleeping last night, when I noticed that there was a perceptible difference in the amount of light the digital clock emanates.


It got me wondering what time displays the most light. Sure I could have manually figured it out, but isn't more exciting to write a script?

Here it is:
<#   Define a lookup table for the amount of light "bars" each number displays. #>           
$hash = @{"1"=2;"2"=5;"3"=5;"4"=4;     
"5"=5;"6"=6;"7"=3;"8"=7;
"9"=5;"0"=6;":"=0}
$max=0
for ($hour = 1; $hour -le 12; $hour++) {
for ($minute = 0;$minute -lt 60; $minute++) {
$time = "{0}:{1:0#}" -f $hour, $minute
$timeArray = $time.ToCharArray()
$sum=0
foreach ($char in $timeArray) {
$sum+= $hash[[string]$char]
}
if ($sum -gt $max) {
$max, $maxTime =$sum, $time
}
}
}
"{0}`t{1}"-f $max, $maxTime
Enjoy!

Project Euler 112

A brute force attack on Project Euler #112. I suspect there is a more efficient algorithm for this (not using string conversions), but this works.
function Test-Bouncy {          
param([int]$num)
$up=$down=$false
$numArray = $num.ToString().ToCharArray()
$length = $numArray.Length
for($i=1; $i -lt $length; $i++) {
if ($numArray[$i-1] -lt $numArray[$i]) {
$up = $true
}
elseif ($numArray[$i-1] -gt $numArray[$i]) {
$down = $true
}
if ($up -and $down) {
return $true
}
}
return $false
}

$isBouncy = $ratio = 0
$x = 1
while ($ratio -lt .99) {
if(Test-Bouncy $x) {
$isBouncy++
$ratio = $isBouncy/$x
}
$x++
}

"{0}`t{1}" -f ($x-1),$ratio
Enjoy!