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!