PowerShell Guid Fun
Updated: May 5, 2010
I recently had a need to dig out this old post, and found that between PowerShell 1 and 2, these index numbers changed. So, I have updated the code below to work with the zero-based indexes.
Original from September 20, 2007 with updated code:
Here's something in my PowerShell startup profile which I find myself using in work with Exchange 2003 and Active Directory. AD stores the MSExchMailboxGuid in a different format than the Guid returned by Exchange in WMI queries (ex: Exchange_Mailbox class). This is handy for outputting to a directorysearcher filter parameter and adds the necessary backslashes.
function Convert-ExchToAdGuid {
param ([string] $exchguid)
$g = $exchguid
$adguid = “\”+$g[6]+$g[7]+”\”+$g[4]+$g[5]+”\”+$g[2]+$g[3]+”\”+$g[0]+$g[1]+”\”+$g[11]+$g[12]+”\”+$g[9]+$g[10]+”\”+$g[16]+$g[17]+”\”+$g[14]+$g[15]+”\”+$g[19]+$g[20]+”\”+$g[21]+$g[22]+”\”+$g[24]+$g[25]+”\”+$g[26]+$g[27]+”\”+$g[28]+$g[29]+”\”+$g[30]+$g[31]+”\”+$g[32]+$g[33]+”\”+$g[34]+$g[35]
return $adguid
}
The secret decoder ring goes a little something like...
- Sample GUID from Exchange: 12345678-9abc-def0-1234-56789abcdef0
- First group, reverse order in pairs of two, add backslashes = \78\56\34\12
- Second group, reverse order in pairs of two = \bc\9a
- Third group, reverse order in pairs of two = \f0\de
- Fourth group, same order = \12\34
- Fifth group, same order = \56\78\9a\bc\de\f0
From here, you can execute an AD LDAP search on the msExchMailboxGuid attribute.
From Scripts to Modules
When I wrote my post on the PowerShell Audit Reports, it caught the attention of Thomas Lee who decided to take them up and package them into a PowerShell v2 module.
The output of his work is shown on his blog and I think it provides a very nice example for getting from a script repository to a distributable module. I could definitely see the value of this as many of the scripts I use today I share with my coworkers. This would allow me to “package” together these scripts into releases to be distributed.
Good stuff.
PowerShelling Audit Reports
Part of working in corporate IT is the necessity to create and demonstrate compliance with general computing controls. In my environment part of those controls consist of creating exports of the membership of certain Active Directory groups. Since I am a fan of automation I put together some PowerShell scripts to speed up this task but it also comes in handy for those one-off “Who is in such-and-such group?” requests.
First, you’ll need two requirements.
- PowerShell 2.0 CTP (I use the convertto-csv cmdlet that does not exist in PSv1. I suppose I could write a routine to do the conversion – but why when 2.0 is coming along nicely?)
- Quest ActiveRoles AD Cmdlets (Once again, I could write the whole thing using System.DirectoryServices, but why when the heavy lifting has been done for you?)
With that out of the way, the routine consists of three different scripts. First, the workhorse of the routine, Get-RecursiveGroupMembership.ps1:
param (
[string] $distinguishedname,
[bool] $addOtherTypes = $false
)
$members = @()$this = (Get-QADGroup $distinguishedname).member | Get-QADObject
$this | foreach {
if ($_.type -eq 'user') {
$members += $_
}
elseif ($_.type -eq 'group') {
Write-Host "Adding sub group $_"
$members += .\Get-RecursiveGroupMembership.ps1 $_.dn $addOtherTypes
}
else {
if ($addOtherTypes -eq $true) {
$members += $_
}
else {
Write-Host "Non user/group member detected. Not added. Use -addOtherTypes flag to add."
}
}
}
return $members
This script is very handy for a lot of things and gives me more power for recursive membership listing than the Get-QADGroupMember cmdlet alone. The other thing that the Get-QADGroupMember cmdlet falls short on is enumerating membership when the group is in another domain – a common occurrence in my environment – hence the use of QADObject and then reading the members attribute.
You will also see the switch. By default the script returns only user objects. You can throw the second parameter (the $addOtherTypes) to true to get all object types.
Future functionality for this script could include a parameter for specifying types to return.
On to the second script, Audit-QuickGroup.ps1, which allows me to pass the distinguishedName of a group in any domain and have the results of that group membership written to a csv file of the same name. This script relies on the first.
param ([string] $name)
$csvdata = .\Get-RecursiveGroupMembership.ps1 $name | select name,type,dn,title,office,description | convertto-csv -NoTypeInformation
$filename = $name + ".csv"
[String]$reportdate = "Report Generated: " + [datetime]::Now
$f = new-item -itemtype file $filename
add-content $f "Audit Report - Active Directory Group - $name"
add-content $f $reportdate
add-content $f $csvdata
This script is pretty simple, taking the output, selecting my most commonly requested attributes, and writing it to a csv file with some header information. Future functionality may include the ability to specify an output filename (optional) and including the header or not.
Lastly, for bulk operations, I needed a way to use the filtering abilities of the Quest Get-QADGroup cmdlet to do the export of multiple groups, written to multiple files with one command. Sure, I could have used a little “Get-QADGroup blah –filter moreblah | foreach { loop previous script }”, but why do that when I can do this in my Audit-MultipleGroups.ps1 script?
# take group input
param ([string] $GroupInput)#get groups
$GroupList = get-qadgroup $groupinput# iterate through groups, creating output
foreach ($Group in $GroupList) {
Write-Host $group.dn
$GroupMembers = .\Get-RecursiveGroupMembership.ps1 $group.DN | select name,type,dn,title,office,description | convertto-csv -NoTypeInformation
#now create file
$filename = $Group.Name + ".csv"
[String]$reportdate = "Report Generated: " + [datetime]::Now
$file = New-Item -ItemType file $filename -Force
Add-Content $file "Audit Report - Active Directory Group Membership"
Add-Content $file $reportDate
Add-Content $file $groupMembers
}
With the swipe of one command, like:
PS> .\Audit-MultopleGroups.ps1 SEC_ADM_*
Provided you have a good Active Directory group naming policy this can output all of the groups matching that prefix into their own csv files with one little command.
So there you go. A very useful base script, a more customer-focused output script, and a purpose-built script all reducing the amount of work necessary to report on group membership in Active Directory. There is one last scenario to deal with in my environment, local computer group membership. The script below will take the computer name and group name as parameters and output the members into a text file. I’ve called it Audit-LocalGroupMembership.ps1.
#local group member enumeration
param (
[string] $Server,
[string] $GroupName
)
$MemberNames = @()
$Group= [ADSI]"WinNT://$Server/$GroupName,group"
$Members = @($Group.psbase.Invoke("Members"))
$Members | ForEach-Object {$MemberNames += $_.GetType().InvokeMember("Name", 'GetProperty', $null, $_, $null)}#file routine
$filename = $server + " " + $GroupName + ".txt"
$f = New-Item -ItemType file $filename
[string]$reportdate = "Date: " + (Get-Date).tostring('yyyyMMdd')
Add-Content $f "Local Group Membership Report"
Add-Content $f "Server: $server"
Add-Content $f "Group : $groupname"
Add-Content $f $reportdate
Add-Content $f $membernames
return $membernames
Happy New Year and happy PowerShelling!
PowerShell One Liner for Directory Lookup
Upon request from one of my coworkers, a one-liner for DN from an AD account name.
$a=read-host; $s=New-Object
directoryservices.directorysearcher("LDAP://dc=yerdomainhere");
$s.filter="(sAMAccountName=$a)"; $s.findone().path
Yeah, sad use of the semicolon I know, but it's a 2 minute job.
Windows Server 2008 admin tools for Vista
Now available and in the "must download" list of software.
Microsoft® Remote Server Administration Tools enables IT administrators to remotely manage roles and features in Windows Server® 2008 from a computer running Windows Vista® with Service Pack 1 (SP1).
Download Link (x86) | Download Link (x64)
While you are out, pick up the HyperV admin console for Vista SP1 as well.