Powershell Needful Things put that in your pipeline

5Aug/091

Legacy mailboxes on Exchange 2007

Posted by Jean Louw

One of our users had a problem logging onto OWA today, and I noticed that the icon for his mailbox in the GUI displayed as a legacy mailbox, although he was located on an Exchange 2007 mailbox server.

After countless searches, I came across this article: http://support.microsoft.com/kb/941146. It explains that the msExchVersion property on the AD object is not set correctly, and that using set-mailbox –ApplyMandatoryProperties would resolve the problem. Looking at the help information on set-mailbox this could also be caused by users being created on Exchange 2007 server using the Exchange 2003 tools, although these users were migrated from Exchange 2003.

So, how to correct this? First get a list of all mailboxes on the Exchange 2007 server with the incorrect version. Using get-mailbox, the incorrect Exchange version displays as 0.0 (6.5.6500.0) The following command returns a list of these mailboxes by server (where SERVER1 is your Exchange 2007 server):

get-mailbox -server SERVER1 -resultsize unlimited | where {$_.ExchangeVersion -like "*0.0*"} | select Name, ExchangeVersion

Once you verify the list, pipe them to set-mailbox.

get-mailbox -server SERVER1 -resultsize unlimited | where {$_.ExchangeVersion -like "*0.0*"} | Set-Mailbox –ApplyMandatoryProperties

This resolved the problem for me, easily, on multiple Exchange mailboxes. Running the get-mailbox command again, returned no results after applying set-mailbox to the problematic mailboxes.

30Jun/096

Cleanup unused Exchange 2007 mailboxes

Posted by Jean Louw

I often use my orphaned home directory cleanup script at work, to recover unused space from our file and print clusters. So my manager recently suggested that I do something similar for Exchange. Knowing that the orphan folder cleanup utility is still my responsibility as the administrators are not too comfortable with running scripts, I decided to give this utility a nice GUI.
To generate the code for the forms, I used SAPIEN PrimalForms. What beautiful tool. Very short learning curve, and very, very powerful. When the form loads, it will get a list of all the Exchange mailbox servers using get-mailboxserver.
This excludes Exchange 2003 servers as get-mailboxstatistics does not work with legacy mailboxes. I may develop a solution for that later. The three query buttons (Disabled, Hidden, Stale) will perform the following actions respectively: Disabled – Find mailboxes linked to disabled AD accounts Hidden – Find mailboxes hidden from the address book.  Stale – Find mailboxes linked to accounts which have not logged on in the last 3 months.
This search may take a little time to complete and this button is not supported against Exchange 2003 servers. These queries will populate the listbox with the names of the mailboxes. Besides the “Export List” button, the Action buttons at the bottom will action only selected items.
You can select items using SHIFT or CTRL. Export List will create a text file containing your search results. Export PST will grant the current user Full Mailbox with Send As and Receive As permission, and then export the mailbox to the path specified. Rename will change the display name based on the query performed. For mailboxes found with the “Disabled” button the display name will be prefixed with “DISABLED-MBXCleaner-“, for “Hidden” with “HIDDEN-MBXCleaner-“ and so forth. Users previously renamed will be excluded from subsequent searches. The “Disable” action will remove Exchange Attributes without deleting the AD account. The mailbox will be removed when the retention time expires. Delete will remove the mailbox and AD account completely.
I have not had a chance to test the Delete button as I would need to submit a change control request before using the utility in our live environment. All of the Action buttons are set to –whatif mode by default. The “Go Hot” checkbox will activate the heavy hitters (Export PST; Rename; Disable and Delete) so you can safely test each button first before taking any action. The “Reserved” button, currently, does nothing. I plan to allow this button to read or build a custom search for users, either by Name or other criteria.
 
WARNING: This is a dangerous utility, and can wreck your Exchange system if you are not careful. Please test this in your test environment first, and adhere to your change control procedures before using this utility in the live environment. I take absolutely no responsibility for any damage caused by using this tool. The utility requires the Exchange Management shell, and if launched from a Vista / Windows 7 needs to be “Run as Administrator”

Full information and the download location for this script can be found here:
http://www.powershellneedfulthings.com/?page_id=293

5Jun/097

Update: Exchange 2007 audit script

Posted by Jean Louw

In an attempt to resolve some issues with regards to the event logs, I have made a few updates to the Exchange 2007 audit script:
* I now use [System.Diagnostics.EventLog]::GetEventLogs() to collect the remote event logs and entries instead of WMI
* The output to the host displays exactly which event log it is busy reading.
* The date range seems more accurate now when the event log contains a large amount of data.
* The physical memory on the basic server information is now displayed as GB and is neatly rounded.
* The Mailbox stores are sorted in alphabetical order by Store Name.
* Added more verbose output to the console while the script runs, to give a better indication of what the script is busy with.
I hope this resolves most of the problems for now, comments / suggestions are always welcome. The script can be downloaded from here:

Complete version and download information can be found here:
http://www.powershellneedfulthings.com/?page_id=276

21May/096

Exchange 2007 Audit Report

Posted by Jean Louw

I had some extra time this week to complete the Exchange 2007 version of the Audit script, as I am going on leave for a week, and needed to have the process automated while I am gone.
This version of the script still uses WMI for some of the items on the report, but uses the Exchange 2007 commandlets for most of the Exchange related information.

The one tricky bit of information to retrieve was the installed Exchange rollups. These are not available via WMI or any other method I could find. I did find a very effective solution on flaphead.com. This little piece of magic, locates the installed patches in the remote registry, and loops through the keys to find and list the installed rollups.


Unlike Exchange 2003, Exchange 2007 servers are installed with specific roles. This plays a part, when checking things like queues and mailbox stores. For instance, there is no point in checking a pure Hub Transport server for mailbox stores etc. I initially built in a check which would check the ServerRole property of the server to match a specific role, forgetting that one server could have multiple roles. I now do a match for the role anywhere in the property string with this if statement: if ($exServer.ServerRole -notlike "*Mailbox*") This will skip the mailbox related check if the word “Mailbox” cannot be located anywhere in the string.

To automate the running of the checks on a daily basis I setup a scheduled task on one of my Exchange 2007 servers as the script requires the commandlets.

I really had no idea how to get the scheduled task to run in the Exchange management shell so, as a test I basically used the following command: C:\WINDOWS\system32\windowspowershell\v1.0\powershell.exe -PSConsoleFile "D:\Program Files\Microsoft\Exchange Server\bin\exshell.psc1" c:\scripts\ExchangeAudit2k7.ps1 .\servers.txt

This did the trick and the entire check process now runs and completes before I even get to work. My version of the script, also creates an HTML menu and moves the reports to our departmental web server for my managers’ viewing pleasure. The mailbox stores now also indicate the last backup time, as we have had issues before where the backups aren't completed, and we don’t find out until it’s too late.

I am busy working on a little piece of code, which will connect to the OWA site and simply test if the site is available, but that will have to wait until I am back from leave.

Complete version and download information can be found here:
http://www.powershellneedfulthings.com/?page_id=276

Filed under: exchange, remote, script, wmi 6 Comments
12May/092

Update: Powershell Remote WMI Defrag

Posted by Jean Louw

As with most things in life, people are only happy with limited features for a little while, and then the enhancement requests pour in.
The administration guys at the office have been using the remote defrag script for a couple of weeks, and soon realised that there was no way for them to show off the results of their labour to management. So inevitably, they requested that I add some sort of reporting to the script which they can send to management.

Initially, I had all the results write out to a text file, for each volume, but this became a mess to manage after you defrag hundreds of servers with multiple volumes. Having recently completed the Exchange 2003 audit script with the use of Virtu-Al’s HTML template, I imagined it would be possible to report the defrag results using a similar format.

The script runs through a list of servers, contained in servers.txt and starts a remote defrag using WMI. It waits for the process to complete and then moves on to the next volume. The script will check if dfrgntfs.exe is running on the remote host, and then skip that server.

The script changes the colour of the drive on the report, based on whether a defrag was actually run or not. Green means it was skipped, orange that defrag was already running and red that it was defragged.
Finally, at the bottom of each drives’ report the script will give you a quick before and after result.

The script can be downloaded from my Skydrive:

17Apr/091

Update Network Interface Card parameters using WMI

Posted by Jean Louw

The following little function can be used if you need to manually override DNS and WINS addresses on a list of remote computers, where they may have already obtained addresses from a DHCP server. The code gets a list of IP enabled NICs from a remote computer using WMI, you can list the servers in servers.txt file in the same folder. The script updates your DNS servers search list to add two manual entries and also adds two manual WINS servers. I had some fun the SetWINSServer method as it only accepts the variable as an array. Finally, the script modifies the registry, to create a DNS suffix search list. Although this script only modifies limited parameters, it can easilly be adapted to update any of the other parameters.
function updateNIC {
$NICs = gwmi -computer $server Win32_NetworkAdapterConfiguration | where{$_.IPEnabled -eq “TRUE”}

foreach ($NIC in $NICs) {

$DNS=("1.1.1.1","2.2.2.2")
$WINS=@("1.1.1.1","2.2.2.2")
$DOMAIN="acme.com"

$NIC.SetDNSServerSearchOrder($DNS)
$NIC.SetDynamicDNSRegistration("TRUE")
$NIC.SetWINSServer($WINS[0],$WINS[1])
$NIC.SetDNSDomain($DOMAIN)

$baseKey = [Microsoft.Win32.RegistryKey]::OpenRemoteBaseKey('LocalMachine', $server)
$baseKey.OpenSubKey
$subKey=$baseKey.OpenSubKey("SYSTEM\\CurrentControlSet\\Services\\Tcpip\\Parameters",$true)
$subkey.SetValue('SearchList','acme.local,acme.com')

}
}
foreach($server in (gc .\servers.txt)){
updateNIC
}
Here are some images of the results of the Advanced TCP/IP Settings page after running the script. Here is the WINS tab.
16Mar/098

Audit the local Administrators group on a list of remote computers

Posted by Jean Louw

This is a very basic script which collects a list of server names from a local text file called servers.txt. The script reports the list of users, sorted by server name to a local text file in the root of drive C. I am working on cleaning up the results, as currently the "Adspath" reports to the text file in the following format: WinNT://DOMAIN/COMPUTER/Administrator This was the only true distinction between local or domain users, as "Name" reports only the name of the user or group. So you are never really sure if it is a domain or local entry. Finally I need to enable the script to report its results to Excel or HTML.

$Result = @()

foreach($server in (gc .\servers.txt)){

$computer = [ADSI](”WinNT://” + $server + “,computer”)
$Group = $computer.psbase.children.find(”Administrators”)

function getAdmins
{$members = $Group.psbase.invoke(”Members”) | %{$_.GetType().InvokeMember(”Adspath”, ‘GetProperty’, $null, $_, $null)}
$members}

$Result += $server
$Result += ( getAdmins )
$Result += " "
}

$Result > c:\results.txt
Invoke-Item c:\results.txt

I had a little extra time today, and managed to clean up the members using the -replace parameter, replace "DOMAIN" with your domain name. The updated code looks something like this:

$Result = @()

foreach($server in (gc .\servers.txt)){

$computer = [ADSI](”WinNT://” + $server + “,computer”)
$Group = $computer.psbase.children.find(”Administrators”)

function getAdmins
{$members = ($Group.psbase.invoke(”Members”) | %{$_.GetType().InvokeMember(”Adspath”, ‘GetProperty’, $null, $_, $null)}) -replace ('WinNT://DOMAIN/' + $server + '/'), '' -replace ('WinNT://DOMAIN/', 'DOMAIN\') -replace ('WinNT://', '')
$members}

$Result += Write-Output "SERVER: $server"
$Result += Write-Output ' '
$Result += ( getAdmins )
$Result += Write-Output '____________________________'
$Result += Write-Output ' '
}



$Result > c:\results.txt

Invoke-Item c:\results.txt

You can simply add another -replace ('WinNT://DOMAIN/', 'DOMAIN\') for each domain in the system. I know its a little hack 'n slash but it will do for now.

11Mar/0922

Automatically clean up orphaned user directories

Posted by Jean Louw

We've had a huge problem where users were removed from Active Directory, but somehow the administrators neglected to remove the home folder for the user from the file servers. This left someone with the nasty task of cleaning up the mess.
This script will work through a directory of home folders and lookup the user in AD. This is assuming that the home folder and the user id are the same. If the user is not found, or the account is disabled, the folder will be renamed with a leading "orphan-" followed by the original name. The script requires a parameter, which is the path where the folders are located. e.g. "findorphans.ps1 c:\users" The script requires that the Quest Powershell Commandlets are installed, and they can be downloaded free, here.

param($target)
$folders=Get-ChildItem -Path $target | Where-Object {$_.Name -notlike "orphan*" -and ($_.PSISContainer)} | Select-Object name
foreach ($folder in $folders){
Write-Host ""
$userid=""
"PROCESSING FOLDER: {0} "   -f $folder.name
write-host "Searching for a possible owner..."
$user=Get-QADUser $folder.name
$useracc=$user.AccountIsDisabled
$userid=$user.samaccountname
$newid="orphan-" + $folder.name
$fullpath=$target + "\" + $folder.name
$fullpath
"Account Disabled: {0} "   -f $user.AccountIsDisabled

if ($userid.length -lt "0" -or $user.AccountIsDisabled -eq "True") {
Write-Host "No owner found or account disabled, orphan folder renamed to" $newid -ForegroundColor Red
rename-Item -Path $fullpath -NewName $newid
}
else {
Write-Host "Owner found" $user -ForegroundColor Green
}
}
10Mar/092

Remote Defrag using WMI

Posted by Jean Louw

This is a script I created to analyze and defrag Windows 2003 server volumes using the WMI win32_volume defrag method.  The script will collect all volumes on a list of remote servers using WMI. Each volume is then analyzed for fragmentation using the FilePercentFragmentation property. If the fragmentation property is higher than 10 the script will initiate a remote defrag on the volume.  You should see a process on the remote server called “dfrgntfs.exe” running while the defrag is in progress. Sadly I have not found a method to track the progress of the defrag process. You can adjust the fragmentation percentage threshold at which a defrag is initiated by editing line 12.  Replace "SERVER1" "SERVER2" with your server names. Comments or suggestions are always welcome.

$servers="SERVER1", "SERVER2"
foreach( $server in $servers){
Write-Host ""
$v=(gwmi win32_volume -computer $server)
"CURRENT SERVER: {0} " -f $server
"NUMBER VOLUMES: {0} " -f $v.length

foreach( $volume in $v){
Write-Host ""
write-host "Analyzing fragmentation on" ($volume.DriveLetter) "..."
$frag=($volume.defraganalysis().defraganalysis).FilePercentFragmentation
if ($frag -gt "10") {
write-host "Drive" ($volume.DriveLetter) "is currently" $frag "% fragmented." -foreground RED
write-host "Starting remote defrag..."
$volume.defrag($true)
}
else {
write-host "Drive" ($volume.DriveLetter) "is not fragmented" -foreground GREEN
Write-Host ""
}
}
}