Windows 2003 Migration

Powershell script to migrate FSRM Quota settings

When migrating file servers, you may need to migrate FSRM based Quota settings.


There can be hundreds of these settings based on FSRM Quota templates. This Powershell script migrates FSRM Quota settings from remote server to local computer, including Quota Templates, Admin Options, and Quotas applied to folders.


Sample script output:


As usual, script output is displayed at the console and saved to a log file for future reference.

After running the script the FSRM Quota Templates and FSRM Quotas (applied to folders) can be viewed in the File Server Resource Manager (Server 2012)


File share migration – Phase 4 – Dealing with files that failed to copy

3/17/2015 update:

I updated the Powershell script to report on files and folders copied and the duration it took, and export that information to CSV files.

Running the same command:

Get-FailedFiles (Get-ChildItem -Path .\logs | where { $_.Name.StartsWith('Robo') }).FullName

The script now produces output to the console like:


and saves two CSV files to the current folder. One contains the file/folder copy summary statistics displayed on the console, and the other contains the list of files that failed to copy and the error code

Following Phase 3 of file share migration, phase 4 will deal with the files that failed to copy. Most commonly this is because the files were open at the time Robocopy attempted to copy them and it could not get the necessary file lock. Step 1 of dealing with the files that failed to copy is to identify them. This Powershell script goes through one or more Robocopy log files and parses out the files that failed to copy. The script can be downloaded from the Microsoft script center repository.

Get-FailedFiles -RoboLog .\logs\Robo-Migrate-FileShares_NYFILSRV01P-2015-03-11_05-27-26AM.txt

The script returns a list of files that failed to copy and the corresponding error codes:

Migrate-Files-14This also can be run against a group of files as in:

$FailedFiles = Get-FailedFiles (Get-ChildItem -Path .\logs | where { $_.Name.StartsWith(‘Robo’) }).FullName

This command will parse all the files under .\logs subfolder that start with ‘Robo’ and return the files that failed to copy and their error codes. This can be presented:
$FailedFiles | FT -Auto # in tabular format

Migrate-Files-15$FailedFiles | Out-Gridview # in Powershell ISE Gridview


$FailedFiles | Export-Csv .\FailedFiles.CSV -NoType # or exported to CSV



File share migration – Phase 3 – importing file share information

Following Phase 2 of file share migration, phase 3 will import file share information. That’s share names, associated share paths, and share level permissions. Fortunately, this information is stored under the registry key


During phase 1 of the file share migration, the Get-FileShares function has already copied these registry entries to a .reg file for us and saved it to the source server. Line 4 of the log file identified exact location:

2015.03.11 02:55:09 PM: Information is saved in file \\NYFILSRV01P-SK3\C$\WINDOWS\Shares.reg

To import all these settings simply browse to and double-click on this .reg file from the new Windows 2012 R2 server to import it into the registry.


Click Yes to proceed.

Migrate-Files-12Finally, restart the Server service for the new shares to take effect:


or, of course we can use the Powershell cmdlets Restart-Service and Get-Service


File share migration – Phase 2 – Robocopy

Following Phase 1 of file share discovery, phase 2 will do the initial seeding and copying of all data from the older Windows 2003 file server to the newer Windows 2012 R2 file server. The script can be downloaded from the Microsoft script center repository.

The same script can be used to run a refresh of the data. It will copy newer and changed files every time it runs. If interrupted, the script can simply be run again. Again only newer or changed files will be copied.


  • The same drives must exist on the new 2012 R2 server as the old 2003 server. So, if we have drive letters F, H, M on the older server we must have the same drive letters on the new server.
  • The drives on the new servers must have enough disk space to accommodate all copied data. If the drives on the new file server are formatted using a larger allocation unit size such as 64 KB, actual disk space used on the new server may exceed disk space used on the old server particularly if copying many files under 64 KB each.

Here’s an example output when running this script:


  • Robocopy copies NTFS permissions on files and folders assigned to domain users and groups. It will not copy permissions to files and folders assigned to local users or groups.
  • Robocopy is unaware of inherited NTFS permissions, and will not copy inherited permissions. This is why this script starts from the root of each drive letter to ensure that all NTFS permissions are captured.
  • This script is intended to run in the context of a domain user account with local administrative permissions on both the source and target servers.
  • Robocopy will copy files with paths longer than 256 characters
  • Depending on how much data is being copied, network speed, storage subsystem speed, and whether /IPG option is used with Robocopy to throttle down the copy process, this can take several hours, days, or weeks.

Robocopy options used:

  • /XJ :: eXclude Junction points. (normally included by default).
  • /R:0 :: number of Retries on failed copies. This is set to not retry failed files. Failed files will be addressed in next phases of the file migration.
  • /W:0 :: Wait time between retries: default is 30 seconds. Choosing no waiting here. Again will be addressed in next phases.
  • /IT :: Include Tweaked files (A Tweaked file is defined to be one that exists in both the source and destination, with identical size and time stamp, but different attribute settings).
  • /MIR :: MIRror a directory tree (equivalent to /E plus /PURGE).
  • /COPYALL :: COPY ALL file info (equivalent to /COPY:DATSOU).
  • /NP :: No Progress – don’t display percentage copied.
  • /TEE :: output to console window, as well as the log file.
  • /ZB :: use restartable mode; if access denied use Backup mode.
  • /LOG+:file :: output status to LOG file (append to existing log).

Since this will be run against production servers, you may want to consider the /IPG option:

/IPG:n :: Inter-Packet Gap (ms), to free bandwidth on slow lines.

For example, using /IPG:100 will slow down copying by waiting 100 ms between each packet to reduce the load on the source server. This will also make the migration process and file copy longer.

File share migration – Phase 1 – Discovery

Many organizations are struggling to meet the end of support deadline for Windows 2003 servers coming up on July 14, 2015. It’s staggering the number of Windows 2003 file servers still in production out there. This post is the first in a series that deals with file shares migration from Windows 2003 servers to 2012 R2.

As usual, I’m using Powershell to perform this task. This script contains Get-FileShares function and can be downloaded from the Microsoft Script Center Repository.

This function provides file share information from one or more Windows file servers. This is intended to run from a domain joined Windows 8.1 workstation against one or more file servers in the same domain. However, the source file servers can be Windows 2003 and up as long as Powershell 2.0 or up is installed, and Powershell remoting is configured. For more information on Powershell for Windows 2003 see this post. The function returns information including server name, share name, description, count of currently connected users, and amount of free space on the drive where the share is located. The function also obtains and saves the registry entries for file shares on the source server(s), and provides link(s) to file(s) location. Function output is displayed to screen and saved to log file.

Here’s an example output of running this script against one Windows 2003 file server:

After running the script to load its functions, I used the command:

$Shares = Get-FileShares -ComputerName NYFILSRV01P-SK3 -Passthru


The console output is also saved to a log file under .\logs subfolder similar to this one:


The output can also be viewed in PS ISE:

$Shares | Out-Gridview # shows information in tabular format in PS ISE


This can also be exported to CSV for viewing in Excel:

$Shares | Export-Csv .\NYFILSRV01P-SK3.csv -NoType


Note that CSV is not suited to handle complex data types. XML is more suitable for that. However, if you wish to list share permissions in CSV, we can use a small script like:

‘”ServerName”,”ShareName”,”Path”,”ShareUser”,”SharePerms”,”ShareAccess”‘ |
Out-File .\NYFILSRV01P-SK3b.csv -Encoding ascii
$Shares | % {
$ServerName = $_.ServerName
$ShareName = $_.ShareName
$Path = $_.Path
$SharePerms = $_.SharePerms
$ShareAccess = $_.ShareAccess
$i = 0
$_.ShareUser | % { “””$ServerName””,””$ShareName””,””$Path””,””$_””,””$(if ($SharePerms.Count -ge ($i+1)) {$SharePerms[$i]})””,””$(if ($ShareAccess.Count -ge ($i+1)) {$ShareAccess[$i]})””” | Out-File .\NYFILSRV01P-SK3b.csv -Append -Encoding ascii $i++ }

Migrate-Files-07and the output will look like:



Powershell module including functions to report on and migrate IIS6 websites to IIS8.5

This Powershell module includes functions to report on and migrate web sites from IIS version 6 on windows 2003 servers to IIS 8.5 on Windows 2012 R2 server. There has been many improvements in Internet Information Server since version 6. With Windows 2003 end of life looming on the horizon, this module can help migrate web workloads to Windows 2012 R2.

This module can be downloaded from the Microsoft Script Center Repository. This is intended to be installed and used on the target Windows 2012 R2 server. Functions will remote into the source Windows 2003 server(s) to retrieve website files and settings. Powershell remoting on the source Windows 2003 servers needs to be configured as shown in this post.

The Migrate-WebSite function will migrate websites from IIS 6 on Server 2003 to IIS 8.5 on Server 2012 R2. The source server is left intact. No changes are done to the source Windows 2003 server. The script can be run repeatedly on the same source/target web servers. This will refresh/update files and website settings from the source server, and will over-write files/settings on the target server.

This script will handle and migrate:

  • Redirected websites
  • Websites set on other than typical port 80
  • Websites with multiple bindings
  • Virtual directories
  • HTML, classic ASP, and DotNet websites

This script will NOT migrate SSL certificates

This script is designed to run on the target 2012 R2 web server (Powershell 4). The scriptblocks that interact with Server 2003 have been tested on Powershell 2.

The script will:

  • Set NTFS permissions for NetworkService/Modify and IUSR/ReadAndExecute at the $Webroot folder
    It will update existing permissions, if any.
    I will not downgrade existing permissions
  • Copy the website files from the source server to this server.
    It will make a folder with the same name as the website name under $Webroot
    It will copy source files for all virtual folders if any existed
  • Set application pool & its properties:
    Crete application pool $AppPool if it did not exist
    Set its .NET CLR version to v2.0
    Enable 32-bit applications
    Change ‘Generate Process Model Event Log Entry’ identity to ‘Network Service’
  • Create web site, or update existing site settings
  • Add additional bindings if any existed on the source website
  • Update the website’s web.comfig file for DotNet websites
    Update any paths to reflect the new website path
    Comment out “configSections” in web.config



Powershell script to update web.config file

Function/script to update web.config file. The script can be downloaded from the Microsoft Script Center Repository. Script can:

  • Replace text within web.config file preserving case
  • Remove sections/nodes from web.config file
  • Comment out sections in web.config file

The script will make a backup copy of the web.config file before updating it.


Update-Web.Config -Destination E:\WebSites\ -CommentSection configSections -Verbose


The script comments out the ‘configSections’ section



Update-Web.Config -Destination E:\WebSites\ -OldPath D:\backme.up\websites\\www -Verbose


The script replaces all occurrences of the string ‘D:\backme.up\websites\\www’ with ‘E:\WebSites\’


Update-Web.Config -Destination E:\WebSites\ -RemoveSection ‘/configuration/configSections’ -Verbose


The script removes ‘/configuration/configSections’ section from web.config file


Update-Web.Config -Destination E:\WebSites\ -OldPath D:\backme.up\websites\\www -CommentSection configSections -RemoveSection ‘/configuration/runtime’ -Verbose


The script replaces all occurrences of the string ‘D:\backme.up\websites\\www’ with ‘E:\WebSites\’, comments out ‘configSections’ section, and removes ‘/configuration/runtime’ section from web.config file

Script to get website(s) information from IIS 6 on Windows 2003 servers

With Windows Server 2003 end of life coming up in July 14, 2015, many organizations are busy trying to migrate from Server 2003 to Server 2012 R2. This Powershell script/tool will get web site information for one or more web sites from a Windows 2003 Server running IIS 6.

This script is intended to be run from a Windows 8.1 or Server 2012 R2 machine. It has been tested on Server 2012 R2 (Powershell 4).  However, the scriptblocks that interact with Server 2003 have been tested on Powershell 2. The script will powershell-remote into the Windows 2003 server to retrieve the website(s) information. For more information on Powershell remoting to Server 2003 from Windows 8.1/Server 2012 R2 see this post.

To use this script, download it from the Microsoft Script Center Repository, unblock the file, and run it like:

.\Get-WebSite.ps1 -WebSite -ComputerName MyW2k3Server -AdminName administrator

The script saves the encrypted admin password for future use. If the file does not exist, the user is prompted for the password:


The script output is a PS Object containing:

  • WebSiteName: for example or
  • Bindings: each binding will have hostname, IP, and Port properties
    • if the host header name is bound to * All Unassigned *, the returned IP will be blank
  • Path: local path on web server where the web site resides
    • if the web site is redirected in IIS, this field will contain redirection URL
  • FileCount: number of files in the web site
  • FolderSize: total file size of the web site
  • vFolders: each VirtualFolder will have Path, vFolder, FileCount, FolderSize
    • This will be blank for redirected websites
  • AutoStart: True or False value to indicate whether or not the website is set to auto-start
  • ID: internal ID number used by IIS
  • LogFolder: local path to IIS logs for this web site
  • Server: name of the web server where this web site resides
  • SSL: secure binding (if any). It has IP and Port properties


The output object of this script contains Bindings, SSL, and vFolders properties which are objects having their own properties. The output will not export properly to CSV but can be saved to and retrieved from XML using the Import-Clixml and Export-Clixml cmdlets.

-XML and -CSV are optional parameters of XML and CSV file names. When used, the script will save website raw information in theses filesGet-WebSite003


.\Get-WebSite.ps1 -WebSite, -ComputerName MyW2k3Server -AdminName administrator -Verbose

Get-WebSite004This example returns information about the websites ‘’ and ‘’ on the server ‘MyW2k3Server’. The -Verbose parameter displays progress information.


$MyWebSites = .\Get-WebSite.ps1, MyW2k3Server administrator -Verbose
$MyWebSites | Out-GridView

This example displays the websites’ information in Powershell_ISE Grid View

    select WebSiteName,ID,Server,FileCount,@{N='Size(MB)';
        E={[Math]::Round($_.FolderSize/1MB,0)}} |
            FT -Auto

This example displays the websites’ information on the console screen

$MyWebSites| % {
    $_ | select WebSiteName,ID,Server,FileCount,@{N='Size(MB)';
        E={[Math]::Round($_.FolderSize/1MB,0)}} | FT -Auto 
    $_.Bindings | FT -Auto 
    $_.vFolders | FT -Auto 

This example displays the websites’ information on the console screen, including Bindings and vFolders


$MyWebSites = .\Get-WebSite.ps1 (Get-Content .\mywebsites.txt) MyW2k3Server administrator -Verbose
$MyWebSites | Out-GridView

This example retieves information about each of the websites listed in the .\mywebsites.txt file and displays it to Powershell_ISE Grid View


If the -WebSite parameter is not provided the script will retrieve web sites’ information about all websites on the provided server.

.\Get-WebSite.ps1 -ComputerName MyW2k3Server -AdminName administrator -Verbose

This example will retrieve information on all web sites on server ‘MyW2k3Server’

Powershell remoting to Windows 2003 from Server 2012 R2 or Windows 8.1

With Windows Server 2003 end of life coming up in July 14, 2015, many organizations are busy trying to migrate from Server 2003 to Server 2012 R2. Some try to do in-place migration to Server 2008 R2 then another in-place migration to server 2012 R2. I don’t think this is good idea. It inherits all the issues from the old 2003 system, and I’m sure there are many. This post goes over Powershell remoting into Windows 2003 servers which is first step in many automation/migration processes.

Install Powershell 2 on Server 2003

Download and install PS2 for Server 2003 x86 or x64 version. This is part of Windows Management Framework (Windows PowerShell 2.0, WinRM 2.0, and BITS 4.0)

Create shortcut to PS2 on Server 2003



Make sure WinRM and WinMgmt services are running

In the GUI Computer Management under Services and applications/services or using Powershell:

Get-Service -Name Win*


Make sure the following 2 services are running and startup is set to ‘automatic’

  • WinMgmt (Windows Management Instrumentation)
  • WinRM (Windows Remote Management)

Enable Powershell Remoting on Server 2003

In Powershell run

Enable-PSRemoting -Force -Verbose


That’s it on the Server 2003 side.

Test connectivity

On a Server 2012 R2 or Windows 8.1 workstation with RSAT installed, which is typically running Powershell 4, add the Server 2003 computer to the trusted hosts list if need be. This is often needed if the managing machine and the managed server are not in the same domain:

winrm s winrm/config/client "@{TrustedHosts=""My2003Server""}"

W2k3-004Finally, use a cmdlet like Enter-PSSession to test connectivity:

Enter-PSSession -ComputerName


You can now execute commands on the remote Windows 2003 computer from your Server 2012 R2 or Windows 8.1 management station.

For more information see Secrets of Powershell Remoting ebook by Dave Jones, Tobias Weltner, Dave Wyatt, and Aleksandar Nikolic