blog.powershell.no

On Windows PowerShell and other admin-related topics

Script Template Add-on for PowerGUI Script Editor

As a best practice, most script authors adds a header to their scripts containing some basic information like the script name, the author and version history.

Some commercial script editors, like Idera`s PowerShell Plus, contains script-templates to make this easier. PowerGUI is another commercial editor, available both in a free and Pro version. This product doesn`t contain any script templates by default, however it`s easy to extend the product with needed functionality by building Add-ons. I`ve created an add-on named Script Template, available here.

When creating a new document in the PowerGUI Script editor, the following template is automatically inserted when the Add-on is loaded:

image

The easiest way to install the Add-on is by using Tools->Find Add-ons Online:

image

Search for “script template” and then press “Install”.

If you want to customize the template you can open the file \Documents\WindowsPowerShell\Modules\Add-on.ScriptTemplate\Add-on.ScriptTemplate.psm1 and modify the following section:

001
002
003
004
005
006
007
008
009
010
011
012
013
014
015
$template = @"
###########################################################################
#
# NAME:
#
# AUTHOR: $env:USERNAME
#
# COMMENT:
#
# VERSION HISTORY:
# 1.0 $((get-date).ToShortDateString()) – Initial release
#
###########################################################################

"@

 

Note that the first new document automatically created when opening the PowerGUI Script Editor won`t get pre-filled with the script template header, since the Script Template Add-on isn`t loaded yet. However, all consecutive new documents will get the template automatically.

A similar Add-on is available here for PowerShell ISE, created by PowerShell MVP Ravikanth Chaganti.

If you`re interested in creating your own Add-ons for the PowerGUI Script Editor, have a look at this excellent tutorial created by Kirk Munro and Dmitry Sotnikov.

March 12, 2011 Posted by | Scripting, Windows PowerShell | , | Leave a Comment

DFS-R Health Report for SYSVOL

Distributed File System Replication (DFS-R) was introduced as a replacement for File Replication Service (FRS) in Windows Server 2008, and was further enhanced in Windows Server 2008 R2. When your domain functional level are set to Windows Server 2008, you have the option to migrate SYSVOL-replication from the deprecated FRS to the new and more reliable DFS-R service. A major advantage of using DFS-R over FRS is that FRS copies the whole file when a change are made, while DFS-R only copies the changed bits. This and further details are discussed here. I`ve also included some links in the resource section below on how to perform an FRS to DFS-R migration.

Included in the Windows Server 2008 and Windows Server 2008 R2 are the DFS Management-console as well as several command-line tools for administering DFS. A great built-in feature in these tools is the diagnostic reports.

This is available in the DFS Management-console:

image

As well as from the DfsrAdmin.exe command-line tool:

image

Using this feature we can generate an HTML-report containing a great overview of the replication health for the SYSVOL replication group:

image

Any errors and warnings will be shown with detailed explanations. In addition we can view general information and statistics i.e. regarding free diskspace on the domain controllers, bandwith savings and so on (click on the thumbnail to view):

image

Since the reporting feature are available from the DfsrAdmin.exe command-line tool, it makes it easy to set up a script as a scheduled task that also sends the generated report via e-mail i.e. every morning. I`ve published a simple PowerShell-script to accomplish this which is available here.

Resources

SYSVOL Replication Migration Guide: FRS to DFS Replication (Word-version available here)

Verifying File Replication during the Windows Server 2008 DFSR SYSVOL Migration

DFSR SYSVOL Migration FAQ

Configuring DFSR to a Static Port

FRS to DFSR Migration Tool (not for SYSVOL migration)

December 30, 2010 Posted by | Active Directory management, DFS-R, Scripting, Windows PowerShell, Windows Server 2008, Windows Server 2008 R2 | | 2 Comments

Retrieve number of mailboxes per database in Exchange Server 2010

Mailbox databases in Exchange Server 2010 doesn`t contain any information regarding the numbers of mailboxes stored in them. A common approach to retrieve this information is using the Exchange Management Shell.

Two examples

 1: #Example 1

 

 2: (Get-MailboxDatabase) | ForEach-Object {Write-Host $_.Name (Get-Mailbox -Database $_.Name).Count}

 

 1: #Example 2

 

 2: (Get-MailboxDatabase) | Select-Object Name,@{Name="Number of users";Expression={(Get-Mailbox -Database $_.name).Count}}

 

Either of these works fine if you want to get the number of mailboxes quick and dirty. However, in larger environments, these one-liners may run for a while.

I did a quick measurement using the Measure-Command cmdlet; Example 1 ran for 36 seconds and example 2 ran for 30 seconds. The environment I ran this in got 5 mailbox databases and approximately 1300 mailboxes.

When running these as one-liners from the Exchange Management Shell, or as part of a scheduled task, the performance might not be an issue.

A colleague of mine was using the Cmdlet Extension Scripting Agent to provision new mailboxes to the mailbox database with the least number of mailboxes in it. In this scenario the performance is key. To achieve better performance, we used an LDAP-query using System.DirectoryServices.DirectorySearcher.

Get-MDBMailboxCount function

I created a PowerShell function to retrieve the number of mailboxes per mailbox database using the DN of a mailbox database as an argument.

 function Get-MDBMailboxCount ([string]$DN) {

 

$Searcher = New-Object System.DirectoryServices.DirectorySearcher

 

$Searcher.SearchRoot = New-Object System.DirectoryServices.DirectoryEntry ("LDAP://$(([system.directoryservices.activedirectory.domain]::GetCurrentDomain()).Name)")

 

$Searcher.Filter = "(&(objectClass=user)(homeMDB=$DN))"

 

$Searcher.PageSize = 10000

 

$Searcher.SearchScope = "Subtree"

 

$results = $Searcher.FindAll()

$returnValue = $results.Count

#dispose of the search and results properly to avoid a memory leak
 $Searcher.Dispose()
 $results.Dispose()

return $returnValue

 

}

 

A problem we stumbled upon was that wildcards didn`t seem to work on the homeMDB-attribute, so we couldn`t use *Mailbox Database Name* for this value.

When looking up on MSDN, it turned out that wildcards are not supported on LDAP DN`s:

For queries that include attributes of DN syntax in a filter, specify full distinguished names. Wildcards (for example, cn=John*) are not supported.

That`s the reason for the function taking DN as an argument, and not the name of a mailbox database.

The function runs the query against the current domain, and hence you don`t need to specify a domain for the LDAP-query.

Back to the performance part, I now ran Measure-Command against the following one-liner:

 1: (Get-MailboxDatabase) | ForEach-Object {Write-Host $_.Name (Get-MDBMailboxCount -DN $_.DistinguishedName)}

 

This time the performance was 3,7 seconds, almost 10x faster. Actually, using a foreach-loop instead of Foreach-Object also makes it slightly faster; 3,5 seconds. You can read up on the difference between these two approaches here.

Get-MDBMailboxCount script

Having the Get-MDBMailboxCount function, I also decided to create a script using this function, which generates a CSV-file.

The script uses a foreach-loop to go through each database in the Exchange-organization, and then creates a custom object for each database containing the name and number of mailboxes. The custom objects are added to an array which can be used for other things like determining the smallest/largest database. You could also use this information to generate graphs like I showed in this blog-post.

Note that I`ve only tested the above against Exchange Server 2010. I suppose it also should work against Exchange Server 2007, if someone can verify this it would be nice if you could leave a comment below.

Update 04.08.2011: The function has been updated  to avoid a memory leak when the function is called multiple times. Thanks to Weston McNamee for the tip (see his comment below).

November 21, 2010 Posted by | Exchange Server 2010, Exchange Server management, Scripting, Windows PowerShell | | 15 Comments

Generate an installation-report for specific hotfixes using Windows PowerShell

Windows PowerShell 2.0 contains a cmdlet called Get-HotFix, which retrieves installed hotfixes from the local computer or specified remote computers.

This is quite useful when you need to check if a particular hotfix is installed prior to installing new software that requires a specific set of hotfixes, or when a critical security hotfix is released and you want to make sure the hotfix is installed.

The Get-HotFix cmdlet retrieves all hotfixes installed by Component-Based Servicing. If you would like to know more about CBS, I would recommend the article Understanding Component-Based Servicing on the Windows Server Performance Team`s blog.

When you need to check several computers, and maybe also check for several hotfixes, it might be a time consuming process to run Get-HotFix against each computer and also keep track of the status for each computer/hotfix. To ease this scenario, I`ve written a script named Get-HotFixReport.ps1.

 

Get-HotFixReport.ps1 overview

  • Retrieves the computers to run Get-HotFix against using the Get-ADComputer cmdlet, which is available in Microsoft`s PowerShell-module for Active Directory
  • Loops through each computer and creates a custom object for every hotfix, containing information about the installation of the current hotfix for the current computer. Any error that occurs is also stored in the custom object. Get-HotFix are only run if the current computer responds to a ping request.
  • Every custom object are added to an array, which at last are exported to a csv-file.

The following three variables must be customized before running the script:

   1: $Computers = Get-ADComputer -Filter * -Properties Name,Operatingsystem | Where-Object {$_.Operatingsystem -like "*server*"} | Select-Object Name

   2: $HotFix = "KB979744,KB979744,KB983440,KB979099,KB982867,KB977020"

   3: $CsvFilePath = "C:\temp\$hotfix.csv"

The example above retrieves all computer objects in Active Directory running a Windows Server operating system. You may specify only one computer, or a secific Organizational Unit, if required.

In the HotFix-variable you need to specify one or more hotfixes to check for. If more than one are specified, they must be separated with a comma. The hotfix-variable in the example above contains all hotfixes that are the prerequisites to install Exchange Server 2010 SP1 on Windows Server 2008 R2.

The csv-file may be opened in Microsoft Office Excel where it`s possible to apply filters to sort on e.g. “true” in the HotfixInstalled-column:

image

 

Note that the Get-HotFix cmdlet actually leverages the Win32_QuickFixEngineering WMI-class, and thus, it would be possible to run the script under Windows PowerShell 1.0 if you replace Get-HotFix with Get-WmiObject -Class Win32_QuickFixEngineering.

Of course you might also choose other ways to retrieve the computer-list, e.g. a csv-file, a txt-file or by using Quest`s PowerShell commands for Active Directory.

October 31, 2010 Posted by | Desktop management, Remote Management, Scripting, Server management, Windows PowerShell, Windows Update | , , | Leave a Comment

Export BitLocker-information using Windows PowerShell

 

Active Directory can be used to store both Windows BitLocker Drive Encryption recovery information and Trusted Platform Module (TPM) owner information.

On the Microsoft Windows Support site, the following information are provided:

Storage of BitLocker Recovery Information in Active Directory

BitLocker recovery information is stored in a child object of a computer object in Active Directory. That is, the computer object is the container for the BitLocker recovery object.

More than one BitLocker recovery object can exist for each computer object, because there can be more than one recovery password associated with a BitLocker-enabled volume.

Each BitLocker recovery object on a BitLocker-enabled volume has a unique name and contains a globally unique identifier (GUID) for the recovery password.

The name of the BitLocker recovery object is limited to 64 characters because of Active Directory constraints. This name incorporates the recovery password GUID as well as date and time information. The form is:

<Object Creation Date and Time><Recovery Password GUID>

For example:

2005-09-30T17:08:23-08:00{063EA4E1-220C-4293-BA01-4754620A96E7}

The Active Directory common name (cn) for the BitLocker recovery object is ms-FVE-RecoveryInformation and includes attributes such as ms-FVE-RecoveryPassword and ms-FVE-RecoveryGuid.

Storage of TPM Recovery Information in Active Directory

There is only one TPM owner password per computer; therefore the hash of the TPM owner password is stored as an attribute of the computer object in Active Directory. It is stored in Unicode. The attribute has the common name (cn) of ms-TPM-OwnerInformation.

Active Directory Requirements

In order to store BitLocker and TPM information in Active Directory, all domain controllers must run Windows Server 2003 with Service Pack 1 or later. Schema extensions will also need to be installed on servers running Windows Server 2003.

 

To see if a computer has stored any BitLocker Recovery information in Active Directory, you must install the BitLocker Recovery Password Viewer and check the BitLocker Recovery tab on the computer object to see if a Recovery Password are present:

image

Doing this for every computer manually isn`t an option in a domain environment. To ease this task I`ve written a PowerShell-script, available here, that will generate a CSV-file containing all Windows Vista and Windows 7 computer objects in the domain. The CSV-file will contain the following information:

  • Computername
  • OperatingSystem
  • HasBitlockerRecoveryKey
  • HasTPM-OwnerInformation

I haven`t found a way to retrieve ms-FVE-RecoveryInformation objects or msTPM-OwnerInformation information on computer objects using Microsoft`s PowerShell-module for Active Directory. Because of that I`ve leveraged Quest`s free PowerShell Commands for Active Directory.

To retrieve correct information, you must run the script with a user that has been granted the following permission: Read-permission on msFVE-RecoveryInformation objects and Read-permissions on msTPM-OwnerInformation on computer-objects (e.g. Domain Admins).

When the CSV-file is generated, you can use the “Text to columns”-feature in Microsoft Office Excel and save the document as an Excel spreadsheet. Then you can apply filters to sort on e.g. HasBitlockerRecoveryKey or HasTPM-OwnerInformation.

If you`re using the BitLocker feature on other operatingsystems than Windows Vista or Windows 7, i.e. Windows Server 2008 or Windows Server 2008 R2, you may customize the filtering in the computers-variable.

 

BitLocker resources on Microsoft TechNet

BitLocker Drive Encryption

BitLocker Drive Encryption Overview

Backing Up BitLocker and TPM Recovery Information to Active Directory

October 24, 2010 Posted by | BitLocker, Scripting, Windows 7, Windows PowerShell, Windows Vista | | 13 Comments

Using Cmdlet Extension Agents to customize mailbox provisioning in Exchange Server 2010

Exchange Server 2010 introduced a new feature for automatically assigning a database while provisioning mailboxes, which uses the Mailbox Resources Management cmdlet extension agent. This feature are demonstrated and described in further detail in this blog post by Mike Pfeiffer.

While this new feature is a great enhancement to Exchange Server, it`s actually possible to customize it further by using another cmdlet extension agent named Scripting Agent.

There are several common ways to distribute mailboxes to databases:

  • Alphabetically
  • Per location
  • Per department
  • Random

My example will focus on using the alphabetically approach to distribute the mailboxes. I`ve re-used the regular expression switch I wrote in this blog post.

Before we proceed, you might want to read this blog post by Pat Richard on how the Scripting Agent work, as well as reading up on Cmdlet Extension Agents on the Exchange Server TechCenter on Microsoft TechNet.

1. Create a file named ScriptingAgentConfig.xml and save it to the CmdletExtensionAgents-folder which by default are C:\Program Files\Microsoft\Exchange Server\V14\Bin\CmdletExtensionAgents. You can find my sample ScriptingAgentConfig.xml here. You will need to customize the names of the databases, as well as the domain name and the Exchange organization name in the $user.database property. Then you would need to copy the ScriptingAgentConfig.xml to the CmdletExtensionAgents-folder on all Exchange 2010 servers in your organization.

2. From the Exchange Management Shell, run Enable-CmdletExtensionAgent “Scripting Agent”. This will enable the Scripting Agent, which will use the ScriptingAgentConfig.xml file we created.

3. From the Exchange Management Shell, run Disable-CmdletExtensionAgent “Mailbox Resources Management Agent”. The Mailbox Resources Management Agent must be disabled when we want to assign the database for the new mailbox using the Scripting Agent, else the Mailbox Resources Management Agent will take precedence. Alternatively we could have changed the priority of the Scripting Agent.

When the above configuration are in place, it`s time to test the new configuration, which of course should be done in a lab environment prior to putting it to production.

From the Exchange Management Console, create a new mailbox and be sure to not select “Specify the mailbox database rather than using a database automatically selected”:

clip_image002

Alternatively, if using the New-Mailbox cmdlet from the Exchange Management Shell, do not specify the “-Database” parameter.

When the test mailbox are created, verify that the database the new mailbox was assigned to is the expected one. For troubleshooting, I would recommend you to use the “–Verbose” parameter on the New-Mailbox cmdlet.

You can use the very same technique to customize database selection based on i.e. the per department approach, by accessing other properties from $provisioningHandler.UserSpecifiedParameters

October 17, 2010 Posted by | Exchange Server 2010, Exchange Server management, Scripting, Windows PowerShell | , | 1 Comment

Getting an overview of all ActiveSync devices in the Exchange-organization

In Exchange 2007, we can get use the Get-ActiveSyncDeviceStatistics to retrieve statistics for a specific ActiveSync-device. We must supply either a device identity or a mailbox name. In Exchange 2010, the same cmdlet exists, but we also got a new useful cmdlet; Get-ActiveSyncDevice. This cmdlet lists all devices in the organization that have active Microsoft Exchange ActiveSync partnerships.

To provide a way to list all ActiveSync devices in the Exchange organization that works against both Exchange 2007 and Exchange 2010, I`ve created a script named Get-ActiveSyncDeviceInfo.ps1. The script outputs each device as an object, making it easy to work with the results. You might i.e. export all devices to a CSV-file by piping the results to Export-Csv.

You might also create graphs based on the results, like I demonstrated in a previous blog-post.

I`m aware that the script could be more effective, using Get-CASMailbox and a server-side filter to sort out only mailboxes that got the property HasActiveSyncDevicePartnership set to “true”. However, I`ve experienced that this property isn`t reliable. Several mailboxes that does have the HasActiveSyncDevicePartnership set to true doesn`t have an ActiveSync devices associated. You might want to use this approach anyway in larger organizations, although I chose to skip it and rather loop through all mailboxes.

September 26, 2010 Posted by | Exchange ActiveSync, Exchange Server 2007, Exchange Server 2010, Scripting, Windows PowerShell | | 8 Comments

Managing calendar permissions in Exchange Server 2010

In legacy versions of Exchange Server we could use PFDAVAdmin to manage calendar permissions, or alternatively the 3rd party tool SetPerm.
With Exchange Server 2010 calendar permissions can be managed using the *-MailboxFolderPermission cmdlets. While these cmdlets can be used to manage permissions on any mailbox folder, we`ll focus on calendar permissions.

In fact we got 4 *-MailboxFolderPermission cmdlets in Exchange Server 2010:

Since I`ll be focusing on managing default permissions , which is an existing ACL on the calendar folder, we need to use the Set-MailboxFolderPermission cmdlet:

image

To grant “Reviewer”-permissions for the “Default” user, we would run the following:

image

Some companies have a policy that everyone must share their calendars with all users. Since it`s now possible to manage calendar permissions using PowerShell, I`ve written a script to accomplish this task; Set-CalendarPermissions.ps1.

While this script could be scheduled to run on a regular basis, a better approach for managing calendar permissions for new mailboxes are the use of the Scripting Agent which is a part of the Cmdlet Extension Agents, a very useful feature introduced in Exchange Server 2010.

Pat Richards has posted an excellent post on how to automatically modify new mailboxes using the Scripting Agent.

September 20, 2010 Posted by | Exchange Server 2010, Exchange Server management, Scripting, Windows PowerShell | | 22 Comments

Invoke Best Practices Analyzer on remote servers using PowerShell

Best Practices Analyzer (BPA) is a management tool integrated in Windows Server 2008 R2 used to scan server roles according to Microsoft best practice guidelines.

Included in the initial release for Windows Server 2008 R2 are the following BPA models:

  • Active Directory Domain Services
  • Active Directory Certificate Services
  • Domain Name System (DNS) Server
  • Remote Desktop Services
  • Web Server (IIS)

Since then several new BPA models are released and available both as separate downloads as well as through Windows Update:

At the time of this writing, a BPA model for 12 of 17 server roles in Windows Server 2008 R2 are available.
The 5 that are not available are:

  • Active Directory Federation Services (ADFS)
  • Active Directory Lightweight Directory Services (AD LDS)
  • Fax Server
  • Print and Document Services
  • Windows Deployment Services

In Server Manager, a BPA summary are available for each installed server role that an BPA Model exists for:

image

When looking at the properties for an item in BPA you get more information as well as a link to Microsoft TechNet where more information are available for the specific subject:

image

BPA are built as a PowerShell module, meaning that a PowerShell cmdlet (Invoke-BPAModel) are run in the background when you scan a server role from Server Manager:

image

This is a great feature to examine if your server roles are configured according to Microsoft`s best practices, however, if you got many servers it will take some time to log on to each server and scan each server role. In addition you don`t get any centralized reporting this way.

Since BPA are based upon Windows PowerShell it`s possible to solve this using the BPA PowerShell module and PowerShell remoting:

image

image

I`ve created a sample script to accomplish this, named Invoke-BPAModeling, with the following functionality:

  • Invoke BPA for all available server roles on specified remote servers
  • E-mail reporting
  • File reporting to CSV and HTML

You need to customize the initial variables on the top of the script. You can enable/disable reporting using these variables, as well as specify which servers to work against, SMTP server for e-mail reporting and paths to CSV/HTML reports.
By default, only items with a severity of “Error” and “Warning” are reported. You can change this to also include “Informational” severities by configuring IncludeAllSeverities to true.
On the server running the script from, the Active Directory module for PowerShell must be installed if you want to retrieve computer names from Active Directory. In the sample,  the script are configured to retrieve all computer accounts listed with Windows Server 2008 R2 as operating system.
You might choose alternate methods, like importing the computer names from a csv-file.
.
I would recommend that you approve the new BPA models mentioned at the beginning of this blog post in WSUS prior to running the script.
The script requires that PowerShell remoting are enabled and configured on the remote servers. Also note that there is a known issue with the BPA module; When the PowerShell execution policy are set to any other than “Undefined” or “Unrestricted” , an error occurs. I`ll update this blog-post as soon as a fix are provided from Microsoft.

When the script executes, it displays the progress based upon the total number of computers running against:

image

Sample e-mail report containing both CSV and HTML reports as attachment:

image

Sample HTML-report:

image

Sample CSV-report converted to an Excel spreadsheet:

image

Feel free to customize the script for your needs, as well as suggest improvements.

Resources

Best Practices Analyzer on Microsoft TechNet

August 17, 2010 Posted by | Best Practices, Scripting, Windows PowerShell, Windows Server 2008 R2 | | 2 Comments

Automate Active Directory Migration Tool using Windows PowerShell

Active Directory Migration Tool (ADMT) provides the ability to restructure Active Directory domain structures. It allows you to migrate users, groups and computers between domains, both intra-forest and inter-forest. Features includes password migration, SID migration and security translation among several others.
ADMT was recently released in version 3.2, adding support for Windows Server 2008 R2 and Managed Service Accounts. You can find the download here, and the ADMT migration guide here.

ADMT provides three options on how to use it, where the first and maybe most used is the GUI:

image

It`s wizard driven and pretty straightforward to use.
The second option is the admt.exe command line utility:

image

In my opinion this is a pretty good example on how inconsistent various command line tools are compared to PowerShell. Although ADMT is a great tool, hopefully the next version will be rebuilt based on PowerShell.

The third option is scripting. There is a COM-object called ADMT.Migration, and there is a sample VB-script (templatescript.vbs) in the ADMT installation directory (by default C:\Windows\ADMT). This sample script is a good place to start to explore how the COM-object works.

Based on this I`ve written a sample PowerShell script, Invoke-ADMTUserMigration, to migrate user accounts and passwords using Windows PowerShell. This script uses the “ADMTDomain” option, which means that all users from the source OU will be migrated to the target OU. To see other available options, see the ADMT documentation and the sample VBScript. Migrating other objects, like groups and computers, the same way should be pretty easy when comparing Invoke-ADMTUserMigration to templatescript.vbs.

Note that since ADMT is a 32-bit application the script must be run from an x86 instance of Windows PowerShell. It also requires elevated privileges (Run as Administrator). Trying to run it in an x64-bit PowerShell instance or without elevated privileges will result in the following error:
New-Object : Retrieving the COM class factory for component with CLSID {285029CC-5048-4D90-8B38-22D304F513DC} failed du
e to the following error: 80040154.

Before trying to run the script I would recommend that you read the ADMT migration guide and ensures that migration works as expected by running a few test migrations from the GUI.

When this is done, I also would recommend to split the migration in batches as recommended in the migration guide. A maximum of 100 objects at a time might be appropriate. Before moving on to the next batch, check the migration logs (by default in C:\Windows\ADMT\Logs) to see that everything went OK before proceeding.

To take this a step further, I`ve created a function, Migrate-ADMTUser, that migrates a single user object. This would allow you to easily do things like this:
Get-ADUser -Filter {Company -like “Oslo”} | Migrate-ADMTUser

This example combines the Active Directory module for PowerShell with ADMT, allowing us to more fine grained control on what objects to migrate.
Note that both the sample script and sample function I`ve created is meant as a guidance on how to use PowerShell to automate ADMT. The optimal way as I see it would be creating an ADMT PowerShell module with functions for migrate other objects like computers and groups in addition to users and passwords.

Resources

ADMT 3.2: Common Installation Issues

ADMT Guide: Migrating and Restructuring Active Directory Domains (TechNet-version)

August 4, 2010 Posted by | Active Directory management, Migration, Scripting, Windows PowerShell | , , , | 7 Comments

Follow

Get every new post delivered to your Inbox.

Join 51 other followers