Powershell Script to Disable inactive Users

Purpose:
Disable users that have been inactive for 90 days.

Notes:
Have not improved format yet.

Must be run on a DC with Domain Admin rights.

# Get today's date
$date = get-date

# Set variable LLTSlimit to today's date minus 90 days
$LLTSlimit = (Get-Date).AddDays(-90).ToFileTimeUTC().ToString()

# Set variable LDAPfilter as a LDAP filter to only find ACTIVE user accounts (useraccountcontrol piece) that have a lastlogontimestamp of older than 90 days
$LDAPFilter = "(&(objectCategory=Person)(objectClass=User)(lastlogontimestamp<=$LLTSlimit)(!(userAccountControl:1.2.840.113556.1.4.803:=2)))" #output LDAPfilter to txt file for loop dsquery * domainroot -filter $LDAPFilter -limit 0 > D:\scripts\AD Auto Disable\ADUserstoDisable.txt

#if LDaPfilter is not null, we will disable some accounts and send a email else do nothing.
if (($ldapcontent = get-content "D:\scripts\AD Auto Disable\ADUserstoDisable.txt") -ne $NULL)
{

    # Pre-create file to store query results
ECHO "Summary of Users Disabled Due To Inactivity" >  D:\scripts\AD Auto Disable\AutoDisableResults.txt
ECHO "*--------------------------------------------------------*" >> D:\scripts\AD Auto Disable\AutoDisableResults.txt

#Loop through the users that need to be disabled one at a time
FOREACH ($f in get-content D:\scripts\AD Auto Disable\ADUserstoDisable.txt)
{
#Add the user to be disabled to txt file to be emailed out.
$f>>D:\scripts\AD Auto Disable\AutoDisableResults.txt

#get the old description so it can be appended
$olddesc = dsget user $f -desc
$olddesc > D:\scripts\AD Auto Disable\olddesc.txt
$processolddesc = get-content "D:\scripts\AD Auto Disable\olddesc.txt"
$processolddesc = $processolddesc[1]

Update:
There is a better version of this script over at vNucleus.com that David wrote:
http://vnucleus.com/2011/07/use-powershell-to-auto-disable-inactive-active-directory-accounts/

David recently sold his domain and this link no longer works.  As soon as he republishes his site I’ll update the link.

A newer version can now be found here: http://wp.me/p1VY3A-7R

Advertisements

Simple Powershell Script to Disable PCs that have been inactive in AD for 90 Days.

Purpose:
Find PC’s that have been inactive for more than 90 days

Notes:
I haven’t formated this script in the typical fashion I normally do.

Must be run on a DC with Domain Rights.

# Get today's date
$date = get-date

# Set variable LLTSlimit to today's date minus 90 days
$LLTSlimit = (Get-Date).AddDays(-90).ToFileTimeUTC().ToString()

# Set variable LDAPfilter as a LDAP filter to only find ACTIVE user accounts (useraccountcontrol piece) that have a lastlogontimestamp of older than 90 days
$LDAPFilter = "(&(objectCategory=Computer)(objectClass=User)(lastlogontimestamp<=$LLTSlimit)(!(userAccountControl:1.2.840.113556.1.4.803:=2)))"

#output LDAPfilter to txt file for loop
dsquery * domainroot -filter $LDAPFilter -limit 0 > D:\scripts\test.txt

#Loop through the computers that need to be disabled one at a time
FOREACH ($f in get-content D:\scripts\test.txt)
{

#disable computer and append to the old description the note about disabling account
dsmod computer $f -disabled yes -desc "$processolddesc - Disabled due to inactivity on $date"

}

exit

Powershell script to generate and email a DFS Health Report.

Purpose:
This script was used to generate a DFS Health Report and email it to the admin team on a daily basis.

Comments:
I attempted to push the report into the body of the email but Outlook did not like the formatting so instead it was added as an attachment.
This is on a Windows 2008 R2 Server using the old commandline version of DFS and its reporting. The Report does not work in some of the newer version of IE.
To view the report you have to hit F12 and then change the Document Mode: IE quirks to IE5 Quirks

#=====================================================================================================#
#    Copyright 2011 Robert Stacks
#
#    This program is free software: you can redistribute it and/or modify
#    it under the terms of the GNU General Public License as published by
#    the Free Software Foundation, either version 3 of the License, or
#    (at your option) any later version.
#
#    This program is distributed in the hope that it will be useful,
#    but WITHOUT ANY WARRANTY; without even the implied warranty of
#    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
#    GNU General Public License for more details.
#
#    You should have received a copy of the GNU General Public License
#    along with this program.  If not, see <http://www.gnu.org/licenses/>.
#
#=====================================================================================================#
# Author: Robert Stacks
# URL: RandomTechMinutia.wordpress.com
# Date: 11/30/2012
# Updated: 11/30/2012
# Version: 0.1
#
# Purpose:
# Generate a DFS Admin Report and Email it to the admin team it must be viewed with IE due to HTML/Java formatting
#=====================================================================================================#

#Get todays Date
$date = Get-Date

#===========================#
#User Adjustable Variables  #
#===========================#

#Mail Server Variables
$SMTPserver = "mail.domain.com"
$from = "DFSReplicationReport@domain.com"
$to = "Youremail@domain.com"
$subject = "DFS Replication Health Report " + $date
$emailbody = "Attached is the Report"

#DFS Info
#Note: $ReplicationGroup=`"Corp Office to Phoenix`", if your group name has no spaces you can remove the `"
#the dfsadmin command can be a little unforgiving about quotes you may have to adjust your values accordingly.

$ReplicationGroup=`"Your Replication Group`"
$MemeberServer="ServerName"
$SaveReportLocation="C:\DFSReports"

#===========================#
#Main Script                #
#===========================#

#Generate DFS Report

dfsradmin health new /RgName:$ReplicationGroup /RefMemName:$MemeberServer /repname:$SaveReportLocation

# Send email
Send-MailMessage -From $from -To $to -SmtpServer $SMTPserver -Subject $subject -Body "Attached is the DFS Health Report. It must be viewed in IE" -Attachments ("C:\DFSReports\Health-Corp Office to Phoenix.html")

Powershell / Powercli script to report on VMs and their VMDKs

Here is a report I put together to quickly view all VMs their VMDKs and the Datastores those VMDKs are sitting on. This is not meant to be a report to view total storage or free space on either the VMs or their Datastores, nor are we looking for orphaned vmdk files. Although I may add those features to this report later on.

Update 3/13/2014: Script now reports on Size and how the data is presented has been improved.

Issue: Review VMDK files for any that don’t have the same name as the VM names in VCenter.

Purpose: Scan and report on VMware VM’s VMDKs and what Datastores they are tied to.

Side Notes:

  • You must have Powercli installed on the machine this report runs off of.
  • The admin account used must have enough permissions to run the given commands.
  • It is possible to have two VMs in vCenter with the same name. So in the report you may see a single server when in fact it is two separate servers.
  • If that happens you’ll see a single instance of that VM’s name with more than the expected number of disk.
#=====================================================================================================#
# Author: Robert Stacks
# Date: 7/18/2012
# Updated: 3/13/2012
# Verson: 1.1
#
# Purpose: 
# Scan and report on Datastores, and related VM's VMDK visible to vCenter
# 
# Updates:
# 3/12/2012
# - Added a column to show the current host ESXi server, Split Folder from VMDK info, and also added size
# - Fixed some spelling and updated comments
# - Fixed some flow logic and adjusted table row color, table padding, and sizing.
#=====================================================================================================#

#Add Snapins
Add-PSSnapin VMware.VimAutomation.Core

#===========================#
#User Adjustable Variables  #
#===========================#

#Vcenter Logon Info
$ESXserver = "vcenterserver.domain.com"
$ESXuser = "username"
$ESXpassword = "password"

#Mail Server Variables
$SMTPserver = "mail.domain.com"
$from = "VMwareReporter@domain.com"
$to = "sysadmins@domain.com"

#===========================#
#Main Script                #
#===========================#

#Determine if already connected to VCenter and if not connect
if ( $DefaultVIServers.Length -lt 1 )
{
  Connect-VIServer -Server $ESXserver -User $ESXuser -Password $ESXpassword -WarningAction SilentlyContinue | Out-Null
}

# Format html report
$htmlReport = @"
<style type='text/css'>
.heading {
 	color:#0B1ABF;
	font-size:14.0pt;
	font-weight:700;
	font-family:Verdana, sans-serif;
	text-align:left;
	vertical-align:middle;
	height:20.0pt;
	width:416pt;
}
.colnames {
 	color:white;
	font-size:11.0pt;
	font-weight:700;
	font-family:Tahoma, sans-serif;
	text-align:center;
	vertical-align:middle;
	border:.5pt solid windowtext;
	background:#730000;
}
.lblueback {
	color:windowtext;
	font-size:10.0pt;
	font-family:Arial;
	text-align:left;
	vertical-align:middle;
	border:.5pt solid windowtext;
	background:#B8CCE4;
}
.greyback {
	color:windowtext;
	font-size:10.0pt;
	font-family:Arial;
	text-align:left;
	vertical-align:middle;
	border:.5pt solid windowtext;
    #background:#D8D8D8;
}

</style>
<table style='border-collapse:collapse;table-layout:auto;width:auto;padding:5px'>
 <tr style='height:15.0pt'>
   <th colspan=6 height=40 width=auto class="heading">
	<center> VM Datastore Report </center></th>
 </tr>
 <tr>
  <th class="colnames">VM Name</th>
  <th class="colnames">Host</th>
  <th class="colnames">DataStore</th>
  <th class="colnames">Folder</th>
  <th class="colnames">FileName</th>
  <th class="colnames">Size/GB</th>
 </tr>
"@

#get a list of VMs
$vmlist = Get-VM -Server $ESXserver | Sort

#counter to manage alternating row color
$colorcounter = 0

#Master part of the script, loops through each VM and creates table with data
ForEach ($vm in $vmlist)
{	
  #If loop to determine color of Rows related to given VM
  if ($colorcounter%2 -eq 0)
	{
		$tablecell = @"
		<td class='lblueback'>
"@
}
  else 
	{ 
		$tablecell = @"
		<td class='greyback'>
"@
}
  
  # Grab VMDK information and the Datastores tied to them.
  $vmdisk = Get-VM $vm | Get-harddisk
  
  # Split out disks where a VM has more than a single disk, also split out the name of the Datastore
  # from the name/path of the vmdk file, then split the Folder Name from the VMDK name.
  $vmdiskDatastore=($vmdisk | %{$_.Filename.Split('[]')[1]})
  $vmdiskfilename=($vmdisk | %{$_.Filename.Split('[]')[2]})
  $vmdiskFolder=($vmdiskfilename | %{$_.Split('/')[0]})
  $vmdiskVMDK=($vmdiskfilename | %{$_.Split('/')[1]})
  $vmdisksize=($vmdisk | %{$_.CapacityKB})
  
  # determine the length of the array so we know if there was more than one hard drive for a given VM.
  $count = $vmdiskfilename.count - 1
  
  # Begin building the html report, inserting the name of the VM in the 1st Column and Host Name into the 2nd 
  $htmlReport = $htmlReport + 
  "<tr>" + $tablecell + $vm.Name + "</td>" +
  $tablecell + $vm.host.Name + "</td>"
  
  # Based on the number of hard drives in the count value the report is generated in one of two ways
  if($count -le 0)
  {
  	# There is only one hard drive so the values will not be in an array we just need to build the table row with data
  	$htmlReport = $htmlReport + 
	$tablecell + $vmdiskDatastore + "</td>" + 
    $tablecell + $vmdiskFolder + "</td>" +
	$tablecell + $vmdiskVMDK + "</td>" +
	$tablecell + $vmdisksize / 1MB + "</tr>"
  }
  else
  {
  	# There is more than one hard drive, because of table formatting we handle the 1st row different from the 2nd row.  Data is in an array.
  	$htmlReport = $htmlReport +
    $tablecell + $vmdiskDatastore[0] + "</td>" + 
    $tablecell + $vmdiskFolder[0] + "</td>" +
	$tablecell + $vmdiskVMDK[0] + "</td>" +
	$tablecell + $vmdisksize[0] / 1MB + "</tr>"
  
  # There is more than one hard drive so we will loop through the array and and place them in the report
 	$x=1
    While($x -le $count)
	{
    	$htmlReport = $htmlReport +
     	"<tr>" + $tablecell + "" + "</td>" + 
		$tablecell + "" + "</td>" +
    	$tablecell + $vmdiskDatastore[$x] + "</td>" + 
    	$tablecell + $vmdiskFolder[$x] + "</td>" +
		$tablecell + $vmdiskVMDK[$x] + "</td>" +
		$tablecell + $vmdisksize[$x] / 1MB + "</tr>"
		$x= $x+1
  	}
   }
   # value used in conjunction with Foreach and if loop to rotate color in table
   $colorcounter = $colorcounter + 1
 }
 
 # We are done gathering data from vCenter so we disconnect
 Disconnect-VIServer -Server $ESXserver -Force:$true -Confirm:$false

# Send email
$subject = "VMware VM Datastore Report"
$emailbody = $htmlReport
$mailer = New-Object Net.Mail.SMTPclient($SMTPserver)
$msg = New-Object Net.Mail.MailMessage($from, $to, $subject, $emailbody)
$msg.IsBodyHTML = $true
$mailer.send($msg)

Example of output:
datastorereportexample

PDFCreator – Handy PDF Print Server for Free

Recently I was asked to address a problem where remote users wanted to be able to print from a legacy Unix/Pick system that normally uses IP based printers.  The remote users connecting to the office using a client side VPN solution didn’t have access to a IP based Printer at home and needed another solution to get their printouts.  Management also didn’t want to spend a ton of money on the solution.  Working with the Unix team I came up with the solution to deploy a Microsoft Windows based PDF printer solution using PDFCreator (http://www.pdfforge.org/pdfcreator).  PDFCreator allows you to setup multiple printers that can be pre-configured to print PDFs to a specific file share that you as an admin can then manage share/file permission as normal.  Another benefit, you can configure these PDFs to be encrypted and have a password on them.  You can also manage if the PDFs can be printed or copied etc.

We ended up deploying this on its own file and print server and then mapping the users computers to their own individual share.  Then on the unix side we instructed them to print to a printer that was pointed back to a PDF printer set to print to their share.  Each user has their own PDF password as well to insure if they print to the wrong printer/share someone else couldn’t open their files.

Then I setup a simple windows script to wipe files contained in the shares older than 7 days.

There are a few catches which are not well covered in documentation which I outline below:

Here is a diagram sort of outlining what I’m talking about

The 1st Catch you need to setup PDFCreator to run as a service.  A good how to can be found over on this blog here.  In short:

  1. Install the Server 2003 resource kit (link).
  2. Create the service with SC:sc create pdfcreator start= auto binPath= “C:\Program Files\oldResourceKitTools\srvany.exe” DisplayName= “PDFCreator”Note the space between the equals sign and the value; it actually needs to be done that way, or SC won’t work.
  3. Check that that worked:sc query pdfcreator
  4. Mangle the service appropriately to actually run the server version of PDFCreator:Start the service and test it out – a file sent to the PDFCreator printer on the server should now pop out in whichever directory you specified back in step 1, regardless of whether or not anyone’s logged in at the server’s console.
    • Edit the key HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Services\pdfcreator.
    • Add a “Parameters” key.
    • Inside the newly-created key, add a REG_SZ value called “Application”, with the path to the PDFCreator executable as the data.
  5. Start the service and test it out – a file sent to the PDFCreator printer on the server should now pop out in whichever directory you specified back in step 1, regardless of whether or not anyone’s logged in at the server’s console.

The next Catch,  how to set a password on a individual PDF printer, again you have to edit the registry

So for example if you setup a printer and call it prITTEST (Used in my Example)  You would need to edit the key found at HKEY_LOCAL_MACHINE\SOFTWARE\Wow6432Node\PDFCreator\Profiles\prITTEST\Printing\Formats\PDF\Security

Then set the PDFOwnerPasswordString and PDFUserPasswordString with a password.  You also need to enable security by setting PDFOwnerPass, PDFUserPass, and PDFUseSecurity to 1.

One last thing of note, when installing PDFCreator, the ESET AV solution we use in the office reported the program containing a virus.  That said I tested the .exe using several other products and I think this is a false positive.  Likely flagging the Windows Tool bar it wants to install as spam-ware.

Set AD Email Address to PrimarySmtpAddress in matching Exchange Contact

Synopsis
I wrote this little script to address a issue where another admin/help desk/etc created a bunch of exchange contacts for external users and then later we ended up creating some AD accounts for some of those users so they could access some Linux/Unix systems we host. However we ran into a issue where those users had no way to be notified of password’s expire. So to address that I wrote this script Powershell Script to Notify Users of Expired or About to Expire Passwords in Active Directory which worked fine but then I found I couldn’t email some users because I didn’t have a email address for them. I did however have an exchange contact for some of them. So I wrote the follow script to copy their emails from the exchange contact into the AD Email attribute.

Requirements to run script:

Other Notes:
You will see some errors with this script if the Get-MailContact fails to find any info for the user in question. This is ok and is expected.

#Add Snapins
Add-PSSnapin "Quest.ActiveRoles.ADManagement" -ErrorAction SilentlyContinue

$users = Get-QADUser -SearchRoot 'OU=INTERNATIONAL OFFICE USERS,DC=domain,DC=net' -Enabled -PasswordNeverExpires:$false | where {($_.Email -eq $null)}

Foreach ($user in $users)
{
	$contact = Get-MailContact -Identity $user.Name
	if ($contact -ne $null)
	{
		Set-QADUser $user.Name -Email $contact.PrimarySmtpAddress
	}
	
}

How to fix the issue of a user not showing up in the Global Address book.

This little one liner can possibly fix a issue where a user doesn’t show up in the Global Address book.

To run the following powershell script, you must be a Domain Admin and an Exchange Admin.

get-mailbox -resultsize unlimited | Where-Object {$_.PrimarySMTPAddress -ne $_.WindowsEmailAddress} 
| foreach { set-mailbox $_.identity -windowsemailaddress $_.primarySMTPAddress }

Explanation:
This Script will set the Email address field found in Active Directory Users and Computers for a User/Object that has a email account in Exchange to the same value as that set in Exchange as that of the User/Object’s primary SMTP email address.

This will fix the issues where the users doesn’t show up in the global address book.

Finally after running the script you must update the OAB in exchange and all clients must update their local address books by running send and receive.

MS Technet Support Article
http://support.microsoft.com/kb/936197