Finding Group members in AD

This is a simple script that will pull up the names of the members of a given group in AD. I use Excell to collect all the names.


$group = Read-Host "Enter group name to find"
$row = 2
$as = Get-ADGroup $group | Get-ADGroupMember

$xlSummaryAbove = 0 
$xlSortValues = $xlPinYin = 1 
$xlAscending = 1 
$xlDescending = 2
$xl = New-Object -comobject excel.application 
$xl.Visible = $true 
$wb = $xl.Workbooks.Add() 
$ws = $wb.Worksheets.Item(1) 
$row = 2
 $ws.Cells.Item(1,1) = 'First Name'
 $ws.Cells.Item(1,2) = 'Last Name'
 $ws.Cells.Item(1,3) = 'EMail Address'
 $ws.Cells.Item(1,4) = 'samAccountName'
 $range = $ws.range('A1:D1')
 $range.font.bold = 'true' 
foreach ($item in $as) { 
$name = Get-ADUser $item.samAccountName
 $ws.Cells.Item($row,1) = $name.GivenName
 $ws.Cells.Item($row,2) = $name.surname
 $ws.Cells.Item($row,3) = $
 $ws.Cells.Item($row,4) = $name.samAccountName 

# one-column sort --> works 
$range1 = $ws.range('A2:D2500')
$range2 = $ws.range('B2')
[void]$range1.sort($range2, $xlAscending)

Import Contacts for Lync 2010

My goal was to import a contact list for my Lync Client.
The idea was to set up a new user in our group with at least a start of a contact list for our team.

You can find a write up and the code for this here:
You will need to install some stuff before you can use this.
Like the LynkSdkRedist.msi which is included in the zip file that you can download from the above site. .

I found that if you have multiple people with the same name, it will add them all if you do the import.

If you know the email address of the people you want to add to your contacts, you can just create a CSV file like this:


You can add whole distribution groups from the GAL as well.
To add a Distribution Group include this line:

"Dist Group Name from the GAL","DistributionGroup","N/A",""

In this case my group name was NSD. Not sure what the “sip:” is all about, but you need it.
The “True” will cause it to overwrite any names or the whole group if it already exist.

Finding a File Type across several machines

I did this as one of my very first Powershell scripts and I noticed that it did no work as well as I liked so here is another attempt.
This one serches AD for a list of Servers and then looks for MDF ( SQL DB files ) on the D:, E: and F: drives.

function Get-Servers {
	$strCategory = "computer"

$objDomain = New-Object System.DirectoryServices.DirectoryEntry

$objSearcher = New-Object System.DirectoryServices.DirectorySearcher
$objSearcher.SearchRoot = $objDomain
$objSearcher.Filter = ("(objectCategory=$strCategory)")

$colProplist = "name"
foreach ($i in $colPropList){$objSearcher.PropertiesToLoad.Add($i)}

$colResults = $objSearcher.FindAll()

foreach ($objResult in $colResults)
    {$objComputer = $objResult.Properties; $}

function Get-MDF{ 
	[string] $srv   
	Get-ChildItem -path ("\\" + $srv) -Recurse -Filter "*.mdf" -ea continue |
		foreach { 
	       $ws.Cells.Item($row, 3) = $_.FullName 
                $ws.Cells.Item($row, 4) = $_.Length       
                $ws.Cells.Item($row, 5) = $_.LastAccessTime    
                $ws.Cells.Item($row, 6) = $_.CreationTime
                $row++ }
$xlCellTypeLastCell = 11	
$a  = Get-Date -format g
$row = 2 
$xl = New-Object -c excel.application 
$xl.visible = $True
$xl.DisplayAlerts = False
$wb = $xl.workbooks.add() 
$ws = $wb.sheets.item(1) 
$ws.Range("A1:T1").Font.Bold = $true 
$ws.Range("A:A").Font.Bold = $True 
$ws.Cells.Item(1, 1) = "Computer Name"
$ws.Cells.Item(1, 2) = "Date Run: "  + $a
$ws.Cells.Item(1, 3) = "FullName"
$ws.Cells.Item(1, 4) = "Length"    
$ws.Cells.Item(1, 5) = "LastAccessTime"    
$ws.Cells.Item(1, 6) = "CreationTime"

# You could say $computerlist = gc "c:\temp\servers.txt"
# you will need a list of computers, one computer name per line
$computerlist = Get-Servers
 foreach ($srv in $computerlist) 
$used = $ws.usedRange
$lastCell = $used.SpecialCells($xlCellTypeLastCell)
$row = $lastCell.row + 1
$ws.Cells.Item($row, 1) = $srv
$response = Get-WmiObject -query "Select * From Win32_PingStatus Where Address = '$srv'" 
  if( ($response -eq $null) -or ($response.StatusCode -ne 0)) { 
    $ws.Cells.Item($row, 2).Font.ColorIndex = 3 
    $ws.Cells.Item($row, 2) = "Does Not Ping"
    } else { if ($response.TimeToLive -le 64) 
      $ws.Cells.Item($row, 2).Font.ColorIndex = 5
      $ws.Cells.Item($row, 2) = "probably is a Unix host"
       } Else { 
      # Change the path and the extension. If you want all files, remove the -include *.???
      # This might be faster get-childitem  -path \$srvc$ -filter "*.mdb" -r -ea continue |
    	$string = ""
		if(Test-Path \\$srv\D$){
		$srvD = ($srv + "\D$")
				Get-MDF $srvD }
		Else { $string =  "No D: Drive"
		$ws.Cells.Item($row, 2) = $string
			$ws.Cells.Item($row, 2).Font.ColorIndex = 5
		If (Test-Path \\$srv\E$) { 
			$srvE = ($srv + "\E$")	
		Get-MDF $srvE }
		Else { $string = $string + " No E: Drive"
		$ws.Cells.Item($row, 2) = $string
		$ws.Cells.Item($row, 2).Font.ColorIndex = 5
		If (Test-Path \\$srv\F$) { 
		$srvF = ($srv + "\F$")
				Get-MDF $srvF }
		Else { $string = $string + " No F: Drive" 
		$ws.Cells.Item($row, 2) = $string
		$ws.Cells.Item($row, 2).Font.ColorIndex = 5
 $xlWorkbookNormal = -4143 
$wb.SaveAs("C:\Scripts\find_MDFfiles.xlsx", $xlWorkbookNormal )
# close and release resources 
spps -n excel # this will shut down all instances of Excel, so be carefull.
#—- End Script ————–>

Building Excel Reports with PowerShell

I found this on;
Blog Name: The Lonely Administrator
Blog URL:
“Building Excel Reports with PowerShell”

I have yet to figure out how to do a Ping Back so I just copy and paste the whole thing.
Some of the ways he does things are not the way I would do them, but the results are just what you would want.
This script collects Hard Disk usage and displays the results in an Excel file complete with a Graph.
It also puts each computer on your list on its own worksheet.
Lots of good stuff here and much of it can be used for other purposes.

cmdletbinding()] # Coment this and the next line to do just the machine you are running the script on
Param([string[]]$computername=$env:computername) # This will do a list of machines
# $computername=$env:computername # Uncomment to do just the machine you are running the script on
#I hope it goes without saying that Excel needs to be installed
Write-Verbose "Creating Excel application" 
$xl=New-Object -ComObject "Excel.Application" 

#we'll need some constants

Foreach ($computer in $computername) {
    #get disk data
    Write-Verbose "Getting disk data from $computer" 
    $disks=Get-WmiObject -Class Win32_LogicalDisk -ComputerName $computer -Filter "DriveType=3"

    Write-Verbose "Adding Worksheet" 


    $cells.item(1,1)="Disk Drive Report"

    #define some variables to control navigation

    #insert column headings
    Write-Verbose "Adding drive headings" 

    "Drive","SizeGB","FreespaceGB","UsedGB","%Free","%Used" | foreach {

    Write-Verbose "Adding drive data" 
    foreach ($drive in $disks) {
        $cells.item($Row,$col)=($drive.Size - $drive.Freespace)/1GB
        $cells.item($Row,$col)=($drive.Size - $drive.Freespace) / $drive.size

    Write-Verbose "Adding some style" 

    #add some style
    #or set it like this
    $ws.Range("A3:F3").Style = "Heading 2"

    #adjust some column widths
    Write-Verbose "Adjusting column widths" 
    $ws.columns.item("B:B").EntireColumn.AutoFit() | out-null

    #add some conditional formatting
    Write-Verbose "Adding conditional formatting" 

    #get the starting cell
    #get the last cell
    #add the icon set
    $Selection.FormatConditions.AddIconSetCondition() | Out-Null
    $Selection.FormatConditions.item(1).ReverseOrder = $True
    $Selection.FormatConditions.item(1).ShowIconOnly = $False
    $Selection.FormatConditions.item(1).IconSet = $xlIconSet::xl3TrafficLights1
    #insert a graph
    Write-Verbose "Creating a graph" 

    #get the last cell
    #get the last cell


    #add labels
    $chart.seriesCollection(1).Select() | Out-Null
    $chart.SeriesCollection(1).ApplyDataLabels() | out-Null
    #modify the chart title
    $chart.ChartTitle.Text = "Utilization"
    Write-Verbose "Repositioning graph" 
    $ws.shapes.item("Chart 1").top=40
    $ws.shapes.item("Chart 1").left=400

    Write-Verbose "Renaming the worksheet"  
    #rename the worksheet
    #select A1
    $ws.Range("A1").Select() | Out-Null
} #foreach

#delete extra sheets
Write-Verbose "Deleting extra worksheets"

#make Excel visible 

$filepath=Read-Host "Enter a path and filename to save the file"

if ($filepath) {
    Write-Verbose "Saving file to $filepath" 

#end of script
###### End Posh Script ######## 

Power Tip of the Day


Create File Shares Remotely
To create a new file share remotely, you could use the WMI class Win32_Share and its Create() method. Invoke-WmiMethod helps you run WMI methods locally and remotely. To create a new share locally or remotely, try this:

###### Start Posh Script ######## 
$Path = 'C:\'
$Name = 'serviceshare'
$Type = 0
$Maximumallowed = 5
$Description = 'PowerShell Share'
$ComputerName = 'storage1'
$rv = Invoke-WmiMethod -Path 'Win32_Share' -ComputerName $ComputerName -Name Create -ArgumentList $null, $Description, $MaximumAllowed, $Name, $null, $Path, $Type
###### End Posh Script ######## 

This would create a new share called “serviceshare” on the machine “storage1”. Remove the parameter -ComputerName if you want to run the method locally on your machine. Add the parameter -Credential if you want to run the command remotely with a different identity.

Powershell Tip Use -f with N0 (Zero)

Use -f with N0
Often, it is necessary to output numbers, but you may want to control the number of digits and would like to control the formatting. The -f operator can do this and has a trillion options but there’s just one you need to remember: N0 (the “0” is the number zero).
PS> ‘{0:N0}’ -f (8GB/12KB)
It rounds the number so there are no digits after the decimal, and it adds a separator every three numbers if the number is more than 999. Replace “N0” with “N1” or any other number to control the digits after the decimal:
PS> ‘{0:N2}’ -f (8GB/12KB)
Share this tip on: facebook | twitter | linkedin

Show-Command Creates PowerShell-Code for You

PowerTip of the Day, from

Show-Command Creates PowerShell-Code for You

In PowerShell 3.0, there is a cool new cmdlet called Show-Command:

PS> Show-Command Get-Process

It works both in the console and the ISE editor, and when you specify a   cmdlet, a dialog window opens and shows a form that helps you discover and   fill in the cmdlet parameters. Once done, click Copy, then Cancel, and the   complete command line code is available from the clipboard. To insert it into   the console, for example, simply right-click.

The dialog window produced by Show-Command also shows the different   parameter sets (groups of parameters) a cmdlet supports, so you never again   run into issues where you accidentally mix parameters from different   parameter sets.
Share this tip on: facebook |   twitter |   linkedin

Some More Primal Forms tidbits

This is just a reminder for me about how to do some things with Primal Forms.
1. Include a Snapin
2. Add a new line to the $richTextbox

function OnApplicationLoad {
	#Note: This function is not called in Projects
	#Note: This function runs before the form is created
	#Note: To get the script directory in the Packager use: Split-Path $hostinvocation.MyCommand.path
	#Note: To get the console output in the Packager (Windows Mode) use: $ConsoleOutput (Type: System.Collections.ArrayList)
	#Important: Form controls cannot be accessed in this function
	#TODO: Add snapins and custom code to validate the application load
	$q = get-pssnapin Quest* -ea "silentlycontinue"
	If ($ -ne "Quest.ActiveRoles.ADManagement") {
	Add-PSSnapin Quest.ActiveRoles.ADManagement }
	return $true #return true for success or false for failure

function OnApplicationExit {
	#Note: This function is not called in Projects
	#Note: This function runs after the form is closed
	#TODO: Add custom code to clean up and unload snapins when the application exits
	$script:ExitCode = 0 #Set the exit code for the Packager

	#TODO: Initialize Form Controls here

$butonRun = {
	$a = Get-QADMemberOf $UserBox.Text 
	foreach ($item in $a) { $item.Name | Out-File c:\useroutput.txt -Append}
	$richtextbox1.text = [string]::join([environment]::newline, (Get-Content c:\useroutput.txt))
	del c:\useroutput.txt

$BtnExit_Click = {


How can I tell if there is a reboot pending on a Windows 2008 R2 server?

I found my answers here:

###### Start Posh Script ########

function Get-PendingReboot($computer = '.') {
	$hkey		= 'LocalMachine';
	$path_server	= 'SOFTWARE\Microsoft\ServerManager';
	$path_control	= 'SYSTEM\CurrentControlSet\Control';
	$path_session	= join-path $path_control 'Session Manager';
	$path_name	= join-path $path_control 'ComputerName';
	$path_name_old	= join-path $path_name 'ActiveComputerName';
	$path_name_new	= join-path $path_name 'ComputerName';
	$path_wsus = 'SOFTWARE\Microsoft\Windows\CurrentVersion\WindowsUpdate\Auto Update\RebootRequired';
	$pending_rename	= 'PendingFileRenameOperations';
	$pending_rename_2	= 'PendingFileRenameOperations2';
	$attempts	= 'CurrentRebootAttempts';
	$computer_name	= 'ComputerName';

	$num_attempts	= 0;
	$name_old	= $null;
	$name_new	= $null;

	$reg= [Microsoft.Win32.RegistryKey]::OpenRemoteBaseKey($hkey, $computer);

	$key_session	= $reg.OpenSubKey($path_session);
	if ($key_session -ne $null) {
		$session_values	= @($key_session.GetValueNames());
		$key_session.Close() | out-null;

	$key_server	= $reg.OpenSubKey($path_server);
	if ($key_server -ne $null) {
		$num_attempts = $key_server.GetValue($attempts);
		$key_server.Close() | out-null;

	$key_name_old	= $reg.OpenSubKey($path_name_old);
	if ($key_name_old -ne $null) {
		$name_old = $key_name_old.GetValue($computer_name);
		$key_name_old.Close() | out-null;

		$key_name_new	= $reg.OpenSubKey($path_name_new);
		if ($key_name_new -ne $null) {
			$name_new = $key_name_new.GetValue($computer_name);
			$key_name_new.Close() | out-null;
		$key_wsus = $reg.OpenSubKey($path_wsus);
		if ($key_wsus -ne $null) {
		$wsus_values = @($key_wsus.GetValueNames());
		if ($wsus_values) {
		$wsus_rbpending = $true
		} else {
		$wsus_rbpending = $false
		$key_wsus.Close() | out-null;

	$reg.Close() | out-null;
	#modified return section:	
		if ( `
		(($session_values -contains $pending_rename) -or ($session_values -contains $pending_rename_2)) `
		-or (($num_attempts -gt 0) -or ($name_old -ne $name_new)) `
		-or ($wsus_rbpending)) {
		return $true;
		else {
		return $false;