Monday, November 28, 2011

PowerShell: Change Local Admin Password

A colleague needed a way to change the local admin password on several desktops without storing the password in a script or group policy. I came up with the script listed below.


#############################################################################
# Script Name: Change_Local_Admin_Password.ps1
# Version: 1.0
# Last Edited: 11/28/2011
# Description: Changes Local Administrator Account Password on Remote Systems
#############################################################################

#Write Out Blank Line (Easier on the Eyes)
Write-Host ""

#Prompt User for New Password (Stored as Secure String)
$sPwd = Read-Host -assecurestring "Please Enter The New Local Admin Password"

#Create PSCredential with Secure String Password (Needed for Secure String Conversion)
$tempCred = New-Object System.Management.Automation.PSCredential("nada",$sPwd)

#Create Network Credential Using The PSCredential Object
$nc = $tempCred.GetNetworkCredential()

#Pull Plain Text Password from Network Credential Object
$uPwd = $nc.Password.ToString()

Write-Host "" #Same Eyes

#Array of Computer Names that Need Local Admin Password Changed
$computers = @("dept-wrks1.my.domain.net","dept-wrks2.my.domain.net","dept-wrks3..my.domain.net")

foreach($computer in $computers)
{

#Ping Computer Before Attempting Password Change
if (test-connection -computername $computer -quiet)
{

try
{

#Var for WinNT Path to Local Administrator Account on Remote System
$WinNTPath = "WinNT://" + $computer + "/Administrator,User"

#Attach to Local Admin Account
$lAdmin = [ADSI]$WinNTPath

#Set Local Admin Password
$lAdmin.setpassword($uPwd)

Write-Host "Successfully Set Password on " $computer

}
catch
{
#Notify Admin of Failure
Write-Host "Error When Setting Password on " $computer
}

}
else
{
#Notify Admin of Failed Ping
Write-Host "Ping Failed to" $computer
}

}

Thursday, July 28, 2011

C#: FEP Client Alert Notice

As an alternative to running SCCM for Forefront Endpoint Protection alert notices (since you can easily control the client with GPOs and WSUS for status) I wrote up a C# console application that parses the system log to look for virus\malware notifications from the FEP client and then emails the alert message(s) to the system admins. This is just a proof of concept. Ideally you would want to create a Windows service that run this code to parse the log every hour or so.


using System;
using System.Collections.Generic;
using System.Text;
using System.Diagnostics;
using System.Net.Mail;

namespace FEP_Status_Check
{
class Program
{
static void Main(string[] args)
{
//Counter for FEP Alerts
int x = 0;

//String Building for FEP Log Entry Data
StringBuilder stbFEPNotice = new StringBuilder();

//Create Collection of System Log Entries
EventLog elSys = new EventLog("System", ".");
EventLogEntryCollection elecSystem = elSys.Entries;

//Loop Through System Events Collection
foreach (EventLogEntry sysLogEntry in elecSystem)
{
//Check to See if From FEP
if (sysLogEntry.Source.ToString() == "Microsoft Antimalware")
{
//Check to See if Event Took Place Within 2 Hours
if (DateTime.Compare(DateTime.Now.AddMinutes(-60), sysLogEntry.TimeGenerated) < 0)
{
//Check for Virus\Malware Alert or Remediation Action Alert
if (sysLogEntry.InstanceId.ToString() == "1116" || sysLogEntry.InstanceId.ToString() == "1117")
{
//Add Log Entry Text to FEP Notice
stbFEPNotice.Append(sysLogEntry.Message.ToString());
stbFEPNotice.Append("\n\n\n");
//Increment Counter
x++;
}
}


}

}

//Notify Network Admins of Any FEP Alerts
if (x > 0)
{

//Pull Computer Name
string strHostName = System.Environment.MachineName.ToString();
//Create and Send Email Notice
MailMessage mmFEPNotice = new MailMessage("DCAdmins@my.company.com", "admins@my.company.com");
mmFEPNotice.Subject = "FEP Alert Notice from " + strHostName + " on " + DateTime.Now.ToShortDateString();
mmFEPNotice.IsBodyHtml = false;
mmFEPNotice.Body = stbFEPNotice.ToString();
SmtpClient scMail = new SmtpClient("smtp.my.company.com");
scMail.Send(mmFEPNotice);

}


}
}
}

PowerShell: AD DC Failed Logins Report

I wanted to get a summary view of failed login attempts on a network DCs. Came up with this script that parses Windows 2008 R2 DCs security log files for all failed login attempts in the last 24 hours. Then it compiles a totals counts for each IP and host name combo listed in the logs of all the DCs. Sends a quick summary email to the admins.

#############################################################
# Script Name: AD_DCs_Failed_Login_Report.ps1
# Version: 1.0
# Author: Dean Bunn
# Last Edited: 07/26/2011
# Description: Failed Logins Report for DCs
#############################################################

#Array for All Failed Login Entries
$arrFailures = @()
#Array for Reporting
$Summary = @()

#Domain Controller Array
$DCs = @("dc1","dc2","dc3")

foreach($DC in $DCs)
{
#Retrieve Failed Logins on Each DC for the Last 24 Hours
$failedLogins = get-eventlog -computername $DC -logname security -after (get-date).adddays(-1) | where-object {$_.instanceID -eq 4625 }

#Loop Through Each Failed Login
foreach($failedLogin in $failedLogins)
{

#Var for Workstation Name
$workstation = ""
#Var for IP Address
$networkAddress = ""

#Array of Failed Login Log Entry Message (Split by Line Break)
$flM = $failedLogin.message.Split("`n")

#Loop Through Each Line in the Log Entry Message
foreach($fl in $flM)
{
#Check to See if Line has Source Network Address Info
if($fl.Contains("Source Network Address:"))
{
#Remove Unneeded Data from Line
$fl = $fl.Replace("Source Network Address:","")
#Clean UP Network Address Info
$networkAddress = $fl.ToString().Trim()
}

#Check to See if Line has Workstation Info
if($fl.Contains("Workstation Name:"))
{
#Remove Unneeded Data from Line
$fl = $fl.Replace("Workstation Name:","")
#Clean Up Workstation Info
$workstation = $fl.ToString().ToUpper().Trim()
}

}

#Format Failed Login Entry Data Before Adding to Array
$flEntry = $networkAddress + "," + $workstation

#Quick Check to See if IP And Host Name Weren't Empty
if($flEntry.length -gt 1)
{
#Added Failed Entry to Array
$arrFailures += $flEntry
}


}

}

#Create Hashtable for Unique Check
$htReport = @{}

#Loop Through Failed Log Entries Array and Count How Many Failed Logins
foreach($flEntry in $arrFailures)
{
#Int for Counting Failed Login Attempts
$intEC = 0

if(!$htReport.ContainsKey($flEntry))
{
#Loop Again Through Array Looking for IP + Host Name Match
foreach($item in $arrFailures)
{
if($flEntry -eq $item)
{
$intEC = $intEC + 1
}
}

#After Determining Matches, See if Entry Count Added To Report Already
#And Only Report on 10 or Greater Failed Logins for IP + Host Name Pair
if($intEC -gt 10) #
{

#Split Apart IP Host Name Entry to Add It to Report Summary
$arrFlEntry = $flEntry.Split(",")

#Create New PowerShell Object and Assign Data to It
$uEntry = new-Object PSObject
$uEntry | add-Member -memberType noteProperty -name "IP" -Value $arrFlEntry[0].ToString()
$uEntry | add-Member -memberType noteProperty -name "Host Name" -Value $arrFlEntry[1].ToString()
$uEntry | add-Member -memberType noteProperty -name "Failed Logins" -Value $intEC.ToString()
#Add Entry to Summary Array
$Summary += $uEntry

}

#Add Entry Info to Reporting Hashtable
$htReport.add($flEntry,"1")

}

}

#Get Current Short Date
$rptDate = Get-Date -Format d

#Style for HTML Table in ConvertTo-HTML
$a = "<style>"
$a = $a + "TABLE{border-width: 1px;border-style: solid;border-color: black;}"
$a = $a + "TH{border-width: 1px;padding: 5px;border-style: solid;border-color: black;text-align: center;}"
$a = $a + "TD{border-width: 1px;padding: 5px;border-style: solid;border-color: black;text-align: left;}"
$a = $a + "</style>"

#Message Body (Sorted by Failed Login Attempts)
$emsg = $Summary | Sort-Object {[int]$_."Failed Logins"} -descending | ConvertTo-Html -head $a | Out-String

#Settings for Email Message
$messageParameters = @{
Subject = "DCs Failed Logins Report for " + $rptDate
Body = $emsg
From = "DCAdmins@my.company.com"
To = "DCAdmins@my.company.com"
SmtpServer = "smtp.my.company.com"
}
#Send Report Email Message
Send-MailMessage @messageParameters –BodyAsHtml

Wednesday, July 6, 2011

PowerShell: Quick and Simple Network Monitor

Helped someone with a quick network monitoring PowerShell script. They are loading the list of systems from a text file on the locale system.

#Variable for System Count
$x = 0

#Email Message Body
$emsg = "<p>The following computer(s) failed Ping:</p>"

#Report Date
$rptDate = Get-Date

#Load Array of Computer Systems
$networkSystems = Get-Content "C:\data\network_systems.txt"

#Ping Each System in Array
foreach($ns in $networkSystems)
{
#If Ping Fails then Add to Message
if (!(test-connection -computername $ns -quiet))
{
$x = $x + 1
$emsg = $emsg + $ns + "<br />"
}

}

if($x -gt 0)
{
#Settings for Email Message
$messageParameters = @{
Subject = "Failed Ping Report for " + $rptDate
Body = $emsg
From = "report@mycollege.edu"
To = "admin@mycollege.edu"
SmtpServer = "smtp.mycollege.edu"
}
#Send Email Message
Send-MailMessage @messageParameters –BodyAsHtml
}

Thursday, June 30, 2011

PowerShell: AD Delete Non-Staged Computers

Came up with the below script to address the issue of delegated admins that don't stage their computer objects in AD. This script will delete any computer objects in the default Computer container. I scheduled a task to run every half hour that runs under an standard user account (that is a member of no admin groups but has delete access to the container). This way if the delegated admins brain dump and forget to the stage the system they don't have to call me to move it. They just have to wait a half hour before they can add it again.


#########################################################################
# Script Name: AD_Delete_Non_Staged_Computers.ps1
# Version: 1.0
# Author: Dean
# Last Edited: 06/28/2011
# Description: Deletes Non Staged Computers from Default Computers
# Container. Sends Email Report
#########################################################################


#Variable for System Count
$x = 0

#Email Message Body
$emsg = "<p>The following computer(s) were deleted from the Computers container:</p>"

#Email server
$smtpServer = "smtp.mycollege.edu"

#Get Current Short Date
$rptDate = Get-Date

#Query AD for All Computers in OU Computers Container
$objADSI = [ADSI]"LDAP://CN=Computers,DC=MYCOLLEGE,DC=EDU"
$Search = New-Object DirectoryServices.DirectorySearcher($objADSI)
$Search.filter = "(objectClass=computer)"
$Results = $Search.Findall()

#Remove Each Computer Object Listed in Results
foreach($result in $Results)
{
$x = $x + 1
$emsg = $emsg + $result.Properties["cn"][0].ToString().Trim() + "<br />"
$systemCN = "CN=" + $result.Properties["cn"][0].ToString().Trim()
$objADSI.Delete("computer", $systemCN)
}

if($x -gt 0)
{
#Settings for Email Message
$messageParameters = @{
Subject = "Deleted Computer Report " + $rptDate
Body = $emsg
From = "admins@mycollege.edu"
To = "admins@mycollege.edu"
SmtpServer = $smtpServer
}
#Send Email Message
Send-MailMessage @messageParameters –BodyAsHtml
}

Sunday, May 22, 2011

PowerShell: AD Logged On Report

Saw a great post on finding logged on users via PowerShell by Ben Wilkinson
http://gallery.technet.microsoft.com/scriptcenter/d46b1f3b-36a4-4a56-951b-e37815a2df0c

Using Ben's script a starting point, I created a script that emails a logged on report for AD systems. This scripts queries AD for all computer systems that aren't disabled. For each of those AD systems it will ping the system before attempting the WMI command. Added a status field to the report for better troubleshooting of failed connections.


#####################################################################
# Script Name: AD_Logged_On_Report.ps1
# Version: 2.0
# Author: Dean
# Last Edited: 05/22/2011
# Description: Email Report of Logged On Accounts for AD Systems
#####################################################################

#Error Handling
$erroractionpreference = "SilentlyContinue"

#Variable for Email FROM Address
$mFrom = "reporter@my.company.net"
#Variable for EMail TO Address
$mTo = "report-Admins@my.company.net"
#Variable for SMTP Server
$smtp = "smtp.my.company.net"

#Get Current Short Date
$rptDate = Get-Date -Format d

#Array for Reporting Objects
$Summary = @()

#LDAP Search for All Computers in Specific OU
#Filtering on Computers That Aren't Disabled
$ADsPath = [ADSI]"LDAP://DC=MY,DC=COMPANY,DC=NET"
$Search = New-Object DirectoryServices.DirectorySearcher($ADsPath)
$Search.filter = "(&(objectClass=computer)(!userAccountControl=4130)(!userAccountControl=4098))"
$Search.SearchScope = "SubTree"
$ADSystems = $Search.FindAll()

foreach ($ADSystem in $ADSystems)
{

#Pull The Computer Name
$Computer = $ADSystem.Properties["cn"][0].ToString()
#Variables for System Status and Logged On Users
$strStatus = ""
$strLoggedOn = ""

#Ping Computer Before Attempting Remote WMI
if (test-connection -computername $Computer -quiet)
{
$strStatus = "Ping Successful"

#Retrieve Processes on Computer System via WMI Call
$processinfo = @(Get-WmiObject -class win32_process -ComputerName $Computer)

#If Process Listing Not NUll Then Find Processes Owned by Unique Non Default Accounts
if ($processinfo)
{
$users = $processinfo | Foreach-Object {$_.GetOwner().User} |
Where-Object {$_ -ne "NETWORK SERVICE" -and $_ -ne "LOCAL SERVICE" -and $_ -ne "SYSTEM"} |
Sort-Object -Unique

#ADD Unique Accounts to the Logged On Variable
if ($users)
{
foreach ($user in $users)
{
$strLoggedOn = $strLoggedOn + $user.ToLower() + " | "
}
}
#else
#{
#$strLoggedOn = "None"
#}

}
else
{
#Report WMI Call Failure
$strStatus = "WMI Failed"
}

}
else
{
#Report Ping Failure
$strStatus = "Ping Failed"
}

#Clean Up Logged On Variable
if($strLoggedOn.Length -gt 4)
{
$strLoggedOn = $strLoggedOn.Trim().TrimEnd("|")
}

#Create New PowerShell Object and Assign Data to It
$uEntry = new-Object PSObject
$uEntry | add-Member -memberType noteProperty -name "Computer Name" -Value $Computer.ToString().ToUpper()
$uEntry | add-Member -memberType noteProperty -name "Status" -Value $strStatus.ToString()
$uEntry | add-Member -memberType noteProperty -name "Logged On Users" -Value $strLoggedOn.ToString()
#Add Entry to Summary Array
$Summary += $uEntry

}

#Style for HTML Table in ConvertTo-HTML
$a = "<style>"
$a = $a + "TABLE{border-width: 1px;border-style: solid;border-color: black;}"
$a = $a + "TH{border-width: 1px;padding: 5px;border-style: solid;border-color: black;text-align: left;}"
$a = $a + "TD{border-width: 1px;padding: 5px;border-style: solid;border-color: black;text-align: left;}"
$a = $a + "</style>"

#Message Body
$emsg = $Summary | Sort-Object {$_."Computer Name"} | ConvertTo-Html -head $a | Out-String

#Settings for Email Message
$messageParameters = @{
Subject = "Logged On Report for " + $rptDate
Body = $emsg
From = $mFrom
To = $mTo
SmtpServer = $smtp
}
#Send Report Email Message
Send-MailMessage @messageParameters –BodyAsHtml

Write-Host "All Done"

Friday, April 29, 2011

PowerShell: Set Mailbox Quota via AD Account Settings

Using only AD to set mailbox quota sizes.

#######################################################################
# Description: Set Mailbox Quota Sizes for Members of an AD Group
# 2GB Mailbox 2097152 and 1992294
# 1GB Mailbox 1048576 and 996352
#######################################################################

#Retrieve AD Group
$objGroup = [ADSI]"LDAP://CN=BioTech,OU=campusDepts,DC=MYDOMAIN,DC=edu"
#Create Array of Group Members
$objGroupMembers = $objGroup.member

foreach ($user in $objGroupMembers)
{
#Retrieve AD User Info
$userPath = "LDAP://" + $user
$objUser = [ADSI]$userPath

#Check to See of User Account Has a Mailbox
if ($objUser.homeMDB)
{
#Apply to Only Mailboxes with Default DB Setting or Lower Mailbox Quota Limit
if (($objUser.mDBUseDefaults -eq $true) -or ($objUser.mDBOverQuotaLimit -lt 2097152))
{
#Set Prohibit Send
$objUser.mDBOverQuotaLimit = 2097152
$objUser.setInfo()
#Set Issue Warning
$objUser.mDBStorageQuota = 1992294
$objUser.setInfo()
#Set Use Database Defaults Setting
$objUser.mDBUseDefaults = $false
$objUser.setInfo()
#Write Out Accounts Changed (Quick Logging)
Write-Host $objUser.sAMAccountName
}

}

}

Write-Host "All Done"

PowerShell: Set AD User No Expiration

In specified OUs, this script sets all user accounts to not expire account or password.

#Array for OUs
$arrOUs = "LDAP://OU=campusUsers,DC=MYDOMAIN,DC=EDU",
"LDAP://OU=campusStudents,DC=MYDOMAIN,DC=EDU"

$i = 0

#Run Against All Users in Specified OU
foreach ($ou in $arrOUs)
{

$ADsPath = [ADSI]$ou
$Search = New-Object DirectoryServices.DirectorySearcher($ADsPath)
$Search.filter = "(objectClass=user)"
$Search.PageSize = 900
$Search.SearchScope = "SubTree"
$results = $Search.Findall()

foreach($result in $results)
{
#Retrieve User Account
$objUser = $result.GetDirectoryEntry()

#Set Account to Not Expire
$objUser.accountExpires = 0
$objUser.setInfo()

#Pull Password Settings and Convert to Int
$crtUAC = [int]($objUser.userAccountControl.ToString())

#If Account is Enabled and\or Requiring Password Change at Next Login
#Set Password Doesn't Expire
if (($crtUAC -eq 512) -or ($crtUAC -eq 544))
{
$objUser.userAccountControl = 66048
$objUser.setInfo()
}
#Same Thing for Disabled Account; However Leave Disabled
elseif ($crtUAC -eq 514)
{
$objUser.userAccountControl = 66050
$objUser.setInfo()
}

$i = $i + 1

write-host $i

}

}

Write-Host 'All Done'

PowerShell: AD Account Creation and Password Last Change Dates for Individual User

AD Account Creation and Password Last Change Dates for Individual User

# Variable for User ID
$userID = "myUserID"

#Create AD Searcher
$ADsPath = [ADSI]"LDAP://DC=MYDOMAIN,DC=EDU"
$Search = New-Object DirectoryServices.DirectorySearcher($ADsPath)
$Search.filter = "(&(objectClass=user)(sAMAccountName=" + $userID.ToString() + "))"
$Search.SearchScope = "SubTree"
$result = $Search.FindOne()

#Get AD User Account
$objUser = $result.GetDirectoryEntry()

#Check to See If Password Last Set has been Actually Set and Not Default Windows Time
if(($result.Properties["pwdlastset"][0].ToString() -ne "9223372036854775807") -and ($result.Properties["pwdlastset"][0].ToString() -ne "0"))
{
$pwdSetDate = [System.DateTime]::FromFileTime($result.Properties["pwdlastset"][0])
}
else
{
$pwdSetDate = "Not Set"
}

#Write Out User Info
Write-Host "Account Created: " $objUser.whenCreated.ToString()
Write-Host "Last Password Change: " $pwdSetDate

Set Exchange Mailbox ActiveSync Policy for AD Group Members

One unit I support wanted a few AD groups to receive a specific ActiveSync security policy. Below is the script that quickly got it done.

#AD Setting for Multi Domain Forest
Set-ADServerSettings -ViewEntireForest $true

$Depts = "Group1","Group2","Group3"

ForEach ($Dept in $Depts)
{
(get-group $Dept).members | Set-CASMailbox –ActiveSyncMailboxPolicy "EDU Security for Mobile Devices"
}

PowerShell: Adjusting Configured Minimum Mailbox Quota

My new unit's Exchange environment had configured minimum mailbox quotas. Well they decided to up the range and we had to make sure all mailboxes were at least set the new minimum (which is this case was 500 MB).

#AD Setting for Multi Domain Forest
Set-ADServerSettings -ViewEntireForest $true

$mailboxes = get-mailbox -resultsize unlimited | select-object Name,Identity,ProhibitSendQuota,RecipientType,UseDatabaseQuotaDefaults

foreach ($mailbox in $mailboxes)
{
#Only Query User Mailboxes
if ($mailbox.RecipientType.ToString() -eq 'UserMailbox')
{

if ($mailbox.UseDatabaseQuotaDefaults -eq $false)
{
$quota = $mailbox.ProhibitSendQuota.Value.ToMB()

if($quota -lt 500)
{
#Write-Host $mailbox.Name.ToString()
set-mailbox -identity $mailbox.Identity -ProhibitSendQuota 500MB -IssueWarningQuota 475MB
}
}
}
}

Write-Host "All Done"

PowerShell: Mail Enable Migrated AD Groups

Came up with this script when migrating over a unit that had a few AD Groups that were mail enabled. Required that I set the no sender authentication and disable the email address policy due to they migrated their mx record as well.

#AD Setting for Multi Domain Forest
Set-ADServerSettings -ViewEntireForest $true

#Import Group Settings
$uGroups = Import-CSV "c:\users\myaccount\desktop\migrated_groups.csv"

foreach ($uGroup in $uGroups)
{
#Mail Enabled the Group
Enable-DistributionGroup -Identity $uGroup.groupid

#Add Remote Domain Primary SMTP Address to Group's Email Addresses
$uGrp = get-DistributionGroup -identity $uGroup.groupid
$uGrp.EmailAddresses += ("smtp:" + $uGroup.emailaddress)
set-DistributionGroup -identity $uGroup.groupid -EmailAddresses $uGrp.EmailAddresses
#Set No Sender Authentication and Disabled Email Address Policy
set-DistributionGroup -identity $uGroup.groupid -RequireSenderAuthenticationEnabled $false -EmailAddressPolicyEnabled $false
}



==============migrated_groups.csv==========================

groupid,displayname,emailaddress
Sales-Peps,Sales Users,SalesUsers@mydomain.edu
PurchasingUsers,Purchasing Users,PurchasingUsers@mydomain.edu
Marketing,Marketing Users,marketingUsers@mydomain.edu

Report on All ActiveSync Devices Attached to Exchange Mailboxes

Someone wearing a tie decided that we needed a report showing the stats of ActiveSync devices connected to our Exchange environment. Here my Exchange PowerShell script solution to the request.

#AD Setting for Multi Domain Forest
Set-ADServerSettings -ViewEntireForest $true

#Retrieve All Mailboxes...Sort by Display Name -resultsize unlimited
$mailboxes = get-mailbox -resultsize unlimited | sort -property DisplayName |
select-object DisplayName,Alias,Identity

foreach ($mailbox in $mailboxes)
{
#Pull ActiveSync Information for the Mailbox
$devices = get-activesyncdevicestatistics -mailbox $mailbox.identity

#Check to See if Mailbox has ActiveSync Device(s)
if ($devices)
{
#Report on All Devices for Mailbox
foreach ($device in $devices)
{
#Create New PowerShell Object and Assign Data to It
$uEntry = new-Object PSObject
$uEntry | add-Member -memberType noteProperty -name "Display Name" -Value $mailbox.DisplayName
$uEntry | add-Member -memberType noteProperty -name "Alias" -Value $mailbox.Alias
$uEntry | add-Member -memberType noteProperty -name "Device Type" -Value $device.DeviceType
$uEntry | add-Member -memberType noteProperty -name "Device Model" -Value $device.DeviceModel
$uEntry | add-Member -memberType noteProperty -name "First Sync Time" -Value $device.FirstSyncTime
$uEntry | add-Member -memberType noteProperty -name "Last Successful Sync" -Value $device.LastSuccessSync
$uEntry | add-Member -memberType noteProperty -name "Last Sync Attempt" -Value $device.LastSyncAttemptTime
$uEntry | add-Member -memberType noteProperty -name "Device OS" -Value $device.DeviceOS
$uEntry | add-Member -memberType noteProperty -name "Device ID" -Value $device.DeviceId
#Add Entry to Summary Array
$Summary += $uEntry

}
}
}

#Export Summary Info to CSV File
$Summary | Export-CSV ActiveSync_Devices.csv -NoTypeInformation

PowerShell: Get Mailbox Size for Members of Various AD Groups

One task that came up my first month at my current gig was to report on mailbox sizes for each member of various AD groups. Below is Exchange PowerShell script that I came up with.

#AD Setting for Multi Domain Forest
Set-ADServerSettings -ViewEntireForest $true

#Array for Reporting Objects
$Summary = @()

#Array of Requested Dept Codes Which Should AD Group Named After Them
$ADGroups = "Group1","Group2","Group3","Group4","Group5","Group6","Group7"

foreach ($ADGroup in $ADGroups)
{
#Pull AD Group Members
$dPart = (get-group $ADGroup).members

foreach ($dUser in $dPart)
{
#Get Mailbox Stats for Group Member
$mbstats = get-mailboxstatistics $dUser

#Only Report on Users with Actual Mailboxes
if($mbstats.TotalItemSize)
{
#Convert Size Into GBs
$mbsize = ("{0:N2}" -f ($mbstats.TotalItemSize.Value.ToMB()/1024))
#Create New PowerShell Object and Assign Data to It
$uEntry = new-Object PSObject
$uEntry | add-Member -memberType noteProperty -name "Display Name" -Value $mbstats.DisplayName
$uEntry | add-Member -memberType noteProperty -name "Mailbox Size (GB)" -Value $mbsize
$uEntry | add-Member -memberType noteProperty -name "Last Logon Time" -Value $mbstats.LastLogonTime
#Add Entry to Summary Array
$Summary += $uEntry
}

}

}

#Export Summary Info to CSV File
$Summary | Sort-Object {[int]$_."Mailbox Size (GB)"} -Descending | Export-CSV Mailboxes_By_AD_Group.csv -NoTypeInformation

PowerShell: Create Numerous Test Mailboxes

A developer in one the departments I support requested 50 test mailboxes. Below is the PowerShell script I ran to quickly take care of the task.

# AD Setting for Multi Domain Forest
Set-ADServerSettings -ViewEntireForest $true

$password = ConvertTo-SecureString -String 'CreativeThoughtGoesHere2011$' -AsPlainText -Force

for ($i=1; $i -le 50; $i++)
{
$un = "AppTestAccount" + $i
$upn = $un + "@mydomain.edu"
New-Mailbox -UserPrincipalName $upn -Alias $un -Database "EX-MDB-001" -Name $un -OrganizationalUnit "OU=RESOURCEACCOUNTS,DC=MYDOMAIN,DC=EDU" -Password $password -DisplayName $un -ResetPasswordOnNextLogon $false

}

Assign Recursive Rights To Public Folder

Day 90 of new job and finally able to take a break to blog some code. Here is a little diddy that I had to use to grant recursive rights on a Exchange public folder to a distribution group.

# AD Setting for Multi Domain Forest
Set-ADServerSettings -ViewEntireForest $true

$pfs = get-publicfolder -identity "\DeptPublicFolder" -recurse

foreach ($pf in $pfs)
{
# Grant Distribution Group Owner Access to Each Public Folder. Use Groups Exchange Alias
Add-PublicFolderClientPermission -Identity $pf.identity -AccessRights owner -User "DistGroupAlias"
}

Tuesday, January 11, 2011

VBScript: OU Users Password Never Expires

Due to a user migration project, my unit needed a quick way of removing "User must change password at next logon" setting caused by the migration tool for all users in a specific OU. Found that this setting is kept in AD under the userAccountControl property of the user object. Below is link that explains the values. One issue that needed a work around was disabled accounts. If you set the value for "Password Never Expires" then a disabled account is re-enabled, which wouldn't be a good thing for accounts that needed to say disabled. Solved this by a quick if statement that looks for only enabled accounts or accounts with the "User must change..." setting.

Active Directory userAccountControl Values

http://rajnishbhatia19.blogspot.com/2008/11/active-directory-useraccountcontrol.html


'***********************************************************************************
'Script Name: OU_Users_Password_Never_Expires.vbs
'Author: Dean Bunn
'Created: 01/10/11
'Description: Set All Enabled User Accounts in an OU to Password Never Expires
'***********************************************************************************

dim objOU, objUser, intPwdChg

intPwdChg = 66048

objOU="OU=staff,DC=mynetwork,DC=com"

set objOU = GetObject("LDAP://" & objOU)

for each objUser in objOU

if objUser.Class="user" Then

set objUser = GetObject("LDAP://" & objUser.distinguishedName)

if objUser.userAccountControl = 512 OR objUser.userAccountControl = 544 then

objUser.Put "userAccountControl", intPwdChg
objUser.setInfo

end if

end if

next

wscript.echo "All Done"