Monday, July 27, 2015

Maintenance MS SQL Database Indexes Base on the Index PercentageFragmented.

On the MS SQL server, we want to maintenance the database indexes automatically base on the index fragmentation.


First, We run the Index_Evaluation.sql every night. It will check all the indexes on the database.

If the index PercentageFragmented  between 5 and 30, we will insert this index record to INDEX_REORGANIZE_SCHEDULE table.

If the Non-Clustered index PercentageFragmented  >=30, we will insert this index record to NC_INDEX_REBUILD_SCHEDULE table.

If the Clustered index PercentageFragmented  >=30, we will insert this index record to C_INDEX_REBUILD_SCHEDULE table.


Second, We schedule to run Index_Reorganize.sql and NC_Index_Rebuild.sql every night, to reorganize indexes which PercentageFragmented  between 5 and 30, and reindex Non-Clustered indexes which PercentageFragmented  >=30.

Third, We schedule to run C_Index_Rebuild.sql on weekend to reindex Clustered indexes which PercentageFragmented  >=30.

Please change the database name and schedule base on your system.


Here are the SQL code.


Index_Evaluation.sql

--------------------------------------------------------------------------------
-- Evaluate every Index on the Database --
-- Put them to Reorganize or Rebuild schedule table                   --
-- base on the index Fragmentation. --
--                            Author: Victor Hu                                          --
--------------------------------------------------------------------------------

--Specify the database that you want to evaluate the indexes.
USE AdventureWorks2012;
GO

-- Set the Dabatbase that will be checked index information.
/* Begin From Here */
--Declare variables 
DECLARE @command NVARCHAR(4000);
DECLARE @SchemaName NVARCHAR(100);
DECLARE @TableName NVARCHAR(100);
DECLARE @IndexName NVARCHAR (100);
DECLARE @IndexID INT;
DECLARE @TableID INT;
DECLARE @IndexType NVARCHAR(30);
DECLARE @PercentageFragmented FLOAT;
DECLARE @DB_ID INT;
DECLARE @DatabaseID INT;
DECLARE @ONLINE NVARCHAR(30);
DECLARE @FILLFACTOR NVARCHAR(3);
DECLARE @ProductVersion NCHAR(2);
DECLARE @Log_FileName NVARCHAR(500);
DECLARE @SQL NVARCHAR(1000);
DECLARE @drive VARCHAR(2);
DECLARE @Dir NVARCHAR(500);
DECLARE @FileName NVARCHAR(500);

--SET @DB_ID = 7
SET @DB_ID = DB_ID();

/********************************************************************************/
/*Create IndexMaintenance Database                 */
/* Drive : Drive letter */
/* Dytectory : like '\Program Files\Microsoft SQL Server\MSSQL11.MSSQLSERVER\MSSQL\DATA\' */
/* Name : file name on the drive directory , Like 'IndexMaintenance' */
/********************************************************************************/

SELECT @drive = 'C:'
SELECT @Dir = '\Program Files\Microsoft SQL Server\MSSQL11.MSSQLSERVER\MSSQL\DATA\'
SELECT @FileName ='IndexMaintenance'

--------------------------------------------------------------
---- set produc SQL server version                        --  
---- 8% SQL 2000                                             --
---- 9% SQL 2005 and up --
--------------------------------------------------------------
SET @ProductVersion = '9%' 

--Instantiate @ONLINE for later use
SET @ONLINE = '';
IF CAST(SERVERPROPERTY('edition') AS NVARCHAR(30)) LIKE 'Enterprise%' OR CAST(SERVERPROPERTY('edition') AS NVARCHAR(30)) LIKE 'Developer%'  SET @ONLINE = ', ONLINE = ON';

--SET @FILLFACTOR to desired fill factor
SET @FILLFACTOR = '80';
------------------------------ 
------------------------------

IF NOT EXISTS (SELECT name FROM sys.databases WHERE name = 'IndexMaintenance') AND (@drive <> '' AND  @Dir <> '' AND @FileName <>'')
BEGIN
SELECT @FileName  = @drive + @Dir + @FileName +'.mdf'
SELECT @Log_FileName = @FileName + '.ldf'
PRINT @FileName
SET @SQL =
N'CREATE DATABASE [IndexMaintenance] ON (NAME = N' + N'''' + N'IndexMaintenance' + N'''' +
N', FILENAME = N' + N'''' + @FileName + N''''+ N', SIZE = 4, FILEGROWTH = 10%)' +
N' LOG ON (NAME = N' + N'''' + N'Maintenance_log' + N'''' + N', FILENAME = N' + N'''' +
@Log_FileName + N'''' + N' , SIZE = 2, FILEGROWTH = 10%) COLLATE Latin1_General_CI_AS'
EXEC (@SQL) 
PRINT (@SQL) 
END
ELSE 
BEGIN
IF NOT EXISTS (SELECT name FROM sys.databases WHERE name = 'IndexMaintenance')
BEGIN
PRINT ('Please provide Driver, Directory and File name to create database.')
PRINT ('The Program is terminated.')
RETURN --Quit the program
END
END

--------------------------------------
-- Create tables on Database --
--------------------------------------
--Check to see if INDEX_REORGANIZE_SCHEDULE exists, and if not, create it
SET @command = '
USE [IndexMaintenance]
IF NOT EXISTS (SELECT * FROM sys.objects WHERE object_id = OBJECT_ID(N'''+'[dbo].[INDEX_REORGANIZE_SCHEDULE]''' + ') AND TYPE in (N'''+ 'U''' + '))
BEGIN
PRINT ''' + 'Could Not Identify The Index Reorganize Table, Creating Now''' + '
SET ANSI_NULLS ON
SET QUOTED_IDENTIFIER ON
CREATE TABLE [dbo].[INDEX_REORGANIZE_SCHEDULE](
[ID] [int] IDENTITY(1,1),
[DatabaseID] [int] NOT NULL,
[SchemaName] [NVARCHAR](100) NOT NULL,
[TableName] [nvarchar](100) NOT NULL,
[IndexName] [nvarchar](100) NOT NULL,
[TableID] [int] NOT NULL,
[IndexID] [int] NOT NULL,
[IndexType] [nvarchar](30) NOT NULL,
[Fragm] [nvarchar](100) NOT NULL,
[Command] [nvarchar] (220) NOT NULL,
[ReorganizeDate] datetime)
ON [PRIMARY]
END'
EXECUTE SP_EXECUTESQL @command;

--Check to see if NC_INDEX_REBUILD_SCHEDULE exists, and if not, create it
SET @command = '';
SET @command = '
USE [IndexMaintenance]
IF NOT EXISTS (SELECT * FROM sys.objects WHERE object_id = OBJECT_ID(N''' + '[dbo].[NC_INDEX_REBUILD_SCHEDULE]''' + ') AND TYPE in (N''' + 'U''' + '))
BEGIN
PRINT ''' + 'Could Not Identify The NONCLUSTERED Index Rebuild Table, Creating Now''' + '
SET ANSI_NULLS ON
SET QUOTED_IDENTIFIER ON
CREATE TABLE [dbo].[NC_INDEX_REBUILD_SCHEDULE](
[ID] [int] IDENTITY(1,1),
[DatabaseID] [int] NOT NULL,
[SchemaName] [NVARCHAR](100) NOT NULL,
[TableName] [nvarchar](100) NOT NULL,
[IndexName] [nvarchar](100) NOT NULL,
[TableID] [int] NOT NULL,
[IndexID] [int] NOT NULL,
[IndexType] [nvarchar](30) NOT NULL,
[Fragm] [nvarchar](100) NOT NULL,
[Command] [nvarchar] (220) NOT NULL,
[ReindexDate] datetime
ON [PRIMARY]
END'
EXECUTE SP_EXECUTESQL @command;

--Check to see if C_INDEX_REBUILD_SCHEDULE exists, and if not, create it
SET @command = '';
SET @command = '
USE [IndexMaintenance]
IF NOT EXISTS (SELECT * FROM sys.objects WHERE object_id = OBJECT_ID(N''' + '[dbo].[C_INDEX_REBUILD_SCHEDULE]''' + ') AND TYPE in (N''' + 'U''' + '))
BEGIN
PRINT '''+ 'Could Not Identify The CLUSTERED Index Rebuild Table, Creating Now''' + '
SET ANSI_NULLS ON
SET QUOTED_IDENTIFIER ON
CREATE TABLE [dbo].[C_INDEX_REBUILD_SCHEDULE](
[ID] [int] IDENTITY(1,1),
[DatabaseID] [int] NOT NULL,
[SchemaName] [NVARCHAR](100) NOT NULL,
[TableName] [nvarchar](100) NOT NULL,
[IndexName] [nvarchar](100) NOT NULL,
[TableID] [int] NOT NULL,
[IndexID] [int] NOT NULL,
[IndexType] [nvarchar](30) NOT NULL,
[Fragm] [nvarchar](100) NOT NULL,
[Command] [nvarchar] (220) NOT NULL,
[ReindexDate] datetime
ON [PRIMARY]
END'
EXECUTE SP_EXECUTESQL @command;

PRINT 'Checking ' + DB_NAME(@DB_ID) + ' indexes fragmentation.'

--Check to see if temporary work table exists
IF object_id('tempdb..#IndexesEvaluation') is not null 
BEGIN
PRINT 'Identified, Temporary Table, Dropping';
DROP TABLE #IndexesEvaluation;
END

--select the Table Name, Index Name, Table ID, Index ID, Index Type, and the fragmentation percentage of the Index into a temporary workspace
SELECT database_id DatabaseID, sch.name SchemaName ,obj.name TableName, ind.name IndexName, stats.object_id TableID, stats.index_id IndexID, stats.index_type_desc IndexType, avg_fragmentation_in_percent PercentageFragmented
INTO #IndexesEvaluation
FROM sys.dm_db_index_physical_stats (@DB_ID,NULL,NULL,NULL,'detailed') stats 
JOIN sysindexes ind ON (ind.id = stats.object_id and ind.indid = stats.index_id)
JOIN sysobjects obj ON (obj.id = stats.object_id)
JOIN sys.schemas sch ON (obj.uid = sch.schema_id)
WHERE stats.avg_fragmentation_in_percent > 5 and stats.index_id <> 0;

----------------------------------------------------------------------------------------------------------
--INSERT Rows to INDEX_REORGANIZE_SCHEDULE, NC_INDEX_REBUILD_SCHEDULE, C_INDEX_REBUILD_SCHEDULE table --
----------------------------------------------------------------------------------------------------------

DECLARE IndexCursor CURSOR FOR SELECT * FROM #IndexesEvaluation ORDER BY PercentageFragmented DESC;
OPEN IndexCursor
WHILE ( 1=1)
BEGIN
SET @command = '';
FETCH NEXT FROM IndexCursor INTO @DatabaseID, @SchemaName ,@TableName, @IndexName, @TableID, @IndexID, @IndexType, @PercentageFragmented;
IF @@FETCH_STATUS <> 0 
BEGIN
BREAK;
END
IF (@PercentageFragmented < 30.0 )
BEGIN
IF (@ProductVersion = '9%') SET @command = 'ALTER INDEX [' + @IndexName + '] ON [' + @SchemaName + '].[' + @TableName + '] REORGANIZE'
ELSE SET @command = 'DBCC INDEXDEFRAG (0, ' + RTRIM(@TableID) + ',' + RTRIM(@IndexID) + ')'

IF NOT EXISTS (SELECT * FROM [IndexMaintenance].[dbo].[INDEX_REORGANIZE_SCHEDULE] WHERE ([ReorganizeDate] IS NULL AND TableID = @TableID AND IndexID = @IndexID))
BEGIN
INSERT INTO [IndexMaintenance].[dbo].[INDEX_REORGANIZE_SCHEDULE](
[DatabaseID]
,[SchemaName]
,[TableName]
,[IndexName]
,[TableID]
,[IndexID]
,[IndexType]
,[Fragm]
,[Command])
VALUES
(@DatabaseID
,@SchemaName
,@TableName
,@IndexName
,@TableID
,@IndexID
,@IndexType
,@PercentageFragmented
,@command)
PRINT('Inserted record for INDEX_REORGANIZE Table: ' + @SchemaName+ '.'+  @TableName + ', on Index ' + @IndexName)
END
CONTINUE;
END

IF (@PercentageFragmented >= 30.0 AND @IndexType = 'CLUSTERED INDEX') 
BEGIN
IF @ProductVersion = '9%' SET @command = 'ALTER INDEX [' + @IndexName + '] ON [' + @SchemaName + '].[' + @TableName + '] REBUILD WITH (FILLFACTOR = ' + @FILLFACTOR  + @ONLINE + ')'
ELSE SET @command = 'DBCC DBREINDEX([' + @SchemaName + '].['+ @tableName + '],' + @FILLFACTOR + ')'
IF NOT EXISTS (SELECT * FROM [IndexMaintenance].[dbo].[C_INDEX_REBUILD_SCHEDULE] WHERE ([ReindexDate] IS NULL AND TableID = @TableID AND IndexID = @IndexID))
BEGIN
INSERT INTO [IndexMaintenance].[dbo].[C_INDEX_REBUILD_SCHEDULE]
([DatabaseID]
,[SchemaName]
,[TableName]
,[IndexName]
,[TableID]
,[IndexID]
,[IndexType]
,[Fragm]
,[Command])
VALUES
(@DatabaseID
,@SchemaName
,@TableName
,@IndexName
,@TableID
,@IndexID
,@IndexType
,@PercentageFragmented
,@command)
PRINT('Inserted record for C_INDEX_REBUILD Table: ' + @SchemaName + '.' + @TableName + ', on Index ' + @IndexName)
END
CONTINUE;
END

IF (@PercentageFragmented >= 30.0 AND @IndexType <> 'CLUSTERED INDEX')  
BEGIN
IF @ProductVersion = '9%' SET @command = 'ALTER INDEX [' + @IndexName + '] ON [' + @SchemaName + '].[' + @TableName + '] REBUILD WITH (FILLFACTOR = ' + @FILLFACTOR  + @ONLINE + ')'
ELSE SET @command = 'DBCC DBREINDEX(' + @tableName + ',' + @FILLFACTOR + ')'
IF NOT EXISTS (SELECT * FROM [IndexMaintenance].[dbo].[NC_INDEX_REBUILD_SCHEDULE] WHERE ([ReindexDate] IS NULL AND TableID = @TableID AND IndexID = @IndexID))
BEGIN
INSERT INTO [IndexMaintenance].[dbo].[NC_INDEX_REBUILD_SCHEDULE]
([DatabaseID]
,[SchemaName]
,[TableName]
,[IndexName]
,[TableID]
,[IndexID]
,[IndexType]
,[Fragm]
,[Command])
VALUES
(@DatabaseID
,@SchemaName
,@TableName
,@IndexName
,@TableID
,@IndexID
,@IndexType
,@PercentageFragmented
,@command)
PRINT('Inserted record for NC_INDEX_REBUILD Table ' + @SchemaName + '.' + @TableName + ', on Index ' + @IndexName)
END
CONTINUE;
END
END
--Close Cursor And Deallocate
CLOSE IndexCursor
DEALLOCATE IndexCursor



Index_Reorganize.sql


--------------------------------------------------------------
-- Doing Index Reorganize --
--                Author: Victor Hu                              --
--------------------------------------------------------------

--Specify the database that you want to reorganize the indexes.
USE AdventureWorks2012;
GO

DECLARE @Command NVARCHAR(4000);
DECLARE @ID INT;

DECLARE IndexCursor CURSOR FOR  
SELECT ID, Command 
FROM [IndexMaintenance].[dbo].[INDEX_REORGANIZE_SCHEDULE]
WHERE [ReorganizeDate] IS NULL 
OPEN IndexCursor
WHILE 1=1
BEGIN
FETCH NEXT FROM IndexCursor INTO @ID, @Command;
IF @@FETCH_STATUS <> 0
BEGIN
BREAK;
END
BEGIN TRY
EXEC (@command)
UPDATE [IndexMaintenance].[dbo].[INDEX_REORGANIZE_SCHEDULE] SET [ReorganizeDate] = GETDATE() WHERE ID = @ID;
PRINT @command;
END TRY
BEGIN CATCH
PRINT 'Get error when ' + @command;
PRINT 'ErrorMessage: ' + ERROR_MESSAGE();
END CATCH

END
--Close Cursor And Deallocate
CLOSE IndexCursor
DEALLOCATE IndexCursor

EXEC sp_updatestats



NC_Index_Rebuild.sql


--------------------------------------------------------------
-- Doing Nonclustered Index Rebuild --
-- Author: Victor Hu --
--------------------------------------------------------------

--Specify the database that you want to rebuild the indexes.
USE AdventureWorks2012 
GO

DECLARE @Command NVARCHAR(4000);
DECLARE @ID INT;

DECLARE IndexCursor CURSOR FOR  
SELECT ID, Command 
FROM [IndexMaintenance].[dbo].[NC_INDEX_REBUILD_SCHEDULE]
WHERE [ReindexDate] IS NULL 
OPEN IndexCursor
WHILE 1=1
BEGIN
FETCH NEXT FROM IndexCursor INTO @ID, @Command;
IF @@FETCH_STATUS <> 0
BEGIN
BREAK;
END
BEGIN TRY
EXEC (@command)
UPDATE [IndexMaintenance].[dbo].[NC_INDEX_REBUILD_SCHEDULE] SET [ReindexDate] = GETDATE() WHERE ID = @ID;
PRINT @command;
END TRY
BEGIN CATCH
PRINT 'Get error when ' + @command;
PRINT 'ErrorMessage: ' + ERROR_MESSAGE();
END CATCH

END
--Close Cursor And Deallocate
CLOSE IndexCursor
DEALLOCATE IndexCursor


C_Index_Rebuild.sql


--------------------------------------------------------------
-- Doing Clustered Index Rebuild                        --
-- Author: Victor Hu                                       --
--------------------------------------------------------------

--Specify the database that you want to rebuild the indexes.
USE AdventureWorks2012
GO

DECLARE @Command NVARCHAR(4000);
DECLARE @ID INT;

DECLARE IndexCursor CURSOR FOR  
SELECT ID, Command 
FROM [IndexMaintenance].[dbo].[C_INDEX_REBUILD_SCHEDULE]
WHERE [ReindexDate] IS NULL 
OPEN IndexCursor
WHILE 1=1
BEGIN
FETCH NEXT FROM IndexCursor INTO @ID, @Command;
IF @@FETCH_STATUS <> 0
BEGIN
BREAK;
END
BEGIN TRY
EXEC (@command)
UPDATE [IndexMaintenance].[dbo].[C_INDEX_REBUILD_SCHEDULE] SET [ReindexDate] = GETDATE() WHERE ID = @ID;
PRINT @command;
END TRY
BEGIN CATCH
PRINT 'Get error when ' + @command;
PRINT 'ErrorMessage: ' + ERROR_MESSAGE();
END CATCH

END
--Close Cursor And Deallocate
CLOSE IndexCursor
DEALLOCATE IndexCursor


Tuesday, April 21, 2015

US House Price Index Analysis

In the past, I used MiniTab or SPSS to analyse Los Angeles Metro House Price. I also want to analyse all the 401 US Metors' House Price. But it need batch script program to achieve this.
Last yeas, I took the INTRO TO DATA SCIENCE workshop from mysliderule.com. And I found that I can easily to do analyse all the US Metros HPI at a time by using R.
I collected the HPI quarterly data from year 1975 to now. And do a simple exponential regression.
The result looks pretty good. It can easily to show when is a good or not good timing to buy a house. I hope this analysis can be your reference.

*********************************************************************************
You can view all the 401 US Metros House Price Index analysis by click the following link.
US HPI Analysis

*********************************************************************************
We are assume the residual is or most like normal distribution.
Basic on our assume, there should be around 70% of HPI data points locate between the green line and orange line.
Around 15% of HPI data points locate under the green line. On the other words, less than 15% of chance that the HPI lower this green line.
Around 15% of HPI data points locate upper the orange line. On the other words, less than 15% of chance that the HPI higher this orange line.

HPI Example

Mountain View
Data From : http://www.fhfa.gov; http://www.freddiemac.com

Wednesday, April 16, 2014

Using VBScript to Rename "My Computer" Icon to "My Computer + mycomputername" via GPO

Using VBScript to Rename "My Computer" Icon to "My Computer + computername" via GPO


1. Create a VBScript, Name "rename My Computer.vbs". Here is script content.

         option explicit

         dim objNetwork, objShell, strComputer, objFolder, objFolderItem
         Const MY_COMPUTER = &H11&

         Set objNetwork = CreateObject("Wscript.Network")
         Set objShell = CreateObject("Shell.Application")

         strComputer = objNetwork.ComputerName

         Set objFolder = objShell.Namespace(MY_COMPUTER)
         Set objFolderItem = objFolder.Self
         objFolderItem.Name = "My Computer " & strComputer

2. Save VBScript to \\DC\SYSVOL\DomainName\Policies\Scripts\Logon

3. Open Group Policy, on the User Configuration section, go to Windows settings, go to Script(Logon/Logoff), double click on Logon, add the VBScript network path.
     

Friday, November 15, 2013

C# Program web based password try.

Scenario: I just work for a new company. I want to get into some network switch and check the configuration to draw the network diagram and backup the switch configuration. But nobody knows the password in our IT team, and no document mention that. It is bad. :(.
I can reset the switches, but we will lost the configuration. And nobody know what is the current switch setting. The switch provide web console. So I use the C#, Selenium, Chrome web driver, and the password dictionary file to find out the password.

Here is the C# code.
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using OpenQA.Selenium;
using OpenQA.Selenium.Chrome;
using OpenQA.Selenium.Support;
using OpenQA.Selenium.Support.UI;
using System.Threading;
using System.IO;
namespace myFirstSelenium
{
    class Program
    {
        static void Main(string[] args)
        {
            string filePath = "PwDict.txt";
            string url = "http://192.168.1.20/";
            string userName = "admin";
            string password = "";
            string returnValue = "";
            StreamReader fileReader = new StreamReader(filePath);
            try
            {
                password = fileReader.ReadLine();
               
                while (password != null)
                {
                    Console.WriteLine();
                    Console.WriteLine("Trying {0} with username: {1} and password: {2}...",url,userName,password);
                    returnValue = Web.Access(url, userName, password);
                    if (returnValue == "Sucessfull")
                    {
                        break;
                    }
                    password = fileReader.ReadLine();
                }

                if (password == null)
                {
                    Console.WriteLine();
                    Console.WriteLine();
                    Console.WriteLine("***Can not find any password!****");
                }
                else
                {
                    Console.WriteLine();
                    Console.WriteLine();
                    Console.WriteLine("***Congratulation***");
                    Console.WriteLine("We found username: {0} ,and password: {1} for {2}!", userName, password, url);
                }
            }
            finally
            {
                fileReader.Close();
            }
        }

       
    }

    class Web
    {
        #region Access Web Site
        public static string Access (string url, string loginname, string password)
        {
            ChromeOptions options = new ChromeOptions();
            //ChromeOptions options = new ChromeOptions();
            options.AddArguments("--no-proxy-server");
            ChromeDriverService service = ChromeDriverService.CreateDefaultService();
            service.SuppressInitialDiagnosticInformation = true;
         
           
            IWebDriver driver = new ChromeDriver(service, options);
           
            //driver.Navigate().GoToUrl("http://192.168.1.20/");
            driver.Navigate().GoToUrl(url);
            driver.Manage().Timeouts().SetPageLoadTimeout(TimeSpan.FromSeconds(10));

            while (true)
            {
                try
                {
                    driver.SwitchTo().Frame("main");
                    break;
                }
                catch (Exception)
                {
                    int milliseconds = 1000;
                    Thread.Sleep(milliseconds);
                }
            }

            while (true)
            {
                try
                {
                    driver.FindElement(By.Name("Password")).Clear();
                    break;
                }
                catch (Exception)
                {
                    int milliseconds = 1000;
                    Thread.Sleep(milliseconds);
                }
            }

            //driver.SwitchTo().Frame("main");
            driver.FindElement(By.Name("Username")).Clear();
            driver.FindElement(By.Name("Username")).SendKeys(loginname);
            driver.FindElement(By.Name("Password")).Clear();
            driver.FindElement(By.Name("Password")).SendKeys(password);
            driver.FindElement(By.LinkText("OK")).Click();
           
            string page = driver.PageSource;

            if (page.Contains("<title>Error</title>"))
            {
                driver.Close();
                return "Failed";
            }
            else
            {
                return "Sucessfull";
            }
           
        }
        #endregion
    }
}

Wednesday, August 14, 2013

Improve iSCSI Performance

This article copy from http://blogs.microsoft.co.il/blogs/yuval14/archive/2011/07/15/how-to-improve-iscsi-performance.aspx
If you want to know more detail, please go the above link to see.

The following post cover a few tips and tricks that can improve you iSCSI performance.

General
1. Use the latest Microsoft operating System.
2. Update the current ISCSI initiator to the latest version.
3. If it applicable, use a HBA (Host Bus Adapter) with iSCSI accelerator.
4. In some scenarios, you may need to use the latest DSM (Device-Specific Module) software module, that can be obtained from the storage/HBA vendor.
5. ISCSI usually supported in 1 GB or higher infrastructure. Using 10/100 MB infrastructure can lead to low performance/data corruption.
6. Please use a dedicated network adapter/s (or HBA) for iSCSI connection. Combining regular network traffic and iSCSI traffic can lead to performance and security issues.
7. The network switch/s that planed to be used for the iSCSI infrastructure should be certificate for ISCSI traffic.
Note: Not all the common network switches officially support iSCSI.
9. Use the latest driver for the network adapter/HBA card/s.
10. For backup LUN by using direct SAN technology, its recommended to allow the backup server to have a Read only privilege to the required LUN.
11. Although iSCSI support block level transfer over TCP/IP, a regular network issues can lead to performance issues. To avoid performance issues, its recommended to implemented a full network design that includes redundant and optimize Spanning Tree Protocol (STP) implementation.
12. Consider to use Jumbo frame on the iSCSI network (Its specially recommended to environments that planed to be use for large file transfer).

Network Performance
1. Review the current network settings by using the command:
netsh interface tcp show global

2. Consider to optimize the autotuninglevel level by implement one of the following settings:
netsh interface tcp set global autotuninglevel=disabled    
 
3. Consider to disable Chimney Offload State support:
netsh int tcp set global chimney=disabled

4. Consider to disable Receive Side Scaling (RSS) support:
netsh int tcp set global rss=disabled

5. Although its usually supported, don’t use any firewall/routing device in the ISCSI network.

6. Consider to disable EnableICMPRedirect support:
HKEY_LOCAL_MACHINE\System\CurrentControlSet\Services\Tcpip\Parameters
Value DWORD 32bits: EnableICMPRedirect set to "0"

7. To implement a high availably and high performance solution, consider to implement MPIO (Microsoft® Multipath I/O):
Understanding MPIO Features and Components

8. Integrating iSCSI, FCIP, and iFCP technologies required a special care. For start, please review: Mr. Jane Shurtleff article:
IP storage: A review of iSCSI, FCIP, iFCP

Note3:Its recommended to reboot the server after applying this changes.                                    


Thursday, June 6, 2013

VBScript Mount PST File on Outlook

Mount the PST files from list on Outlook.
PST Files list save in pstlist.txt
File Name openpst.vbe

Set objFSO = CreateObject("Scripting.FileSystemObject")
Set objFile = objFSO.OpenTextFile("pstlist.txt")
set objOutlook = createObject("Outlook.Application")
set objMAPI = objOutlook.GetNamespace("MAPI")
do while not objFile.AtEndOfStream
    fPath =  objFile.ReadLine()
    objMAPI.AddStore fPath
loop

VBScript get Outlook PST files list

Get Outlook mounted PST Files list. And save file list to pstlist.txt.

File name: getpstlist.vbe

Set objFSO = CreateObject("Scripting.FileSystemObject")
Set objFile = objFSO.CreateTextFile("pstlist.txt", True)
set objOutlook = createObject("Outlook.Application")
set objMAPI = objOutlook.GetNamespace("MAPI")
for each PSTFolder In objMAPI.Folders
  pstPath = GetPath(PSTFolder.StoreID)
  if pstPath <> "" then
    objFile.WriteLine pstPath
  end if
next
function GetPath(input)
  for i = 1 To Len(input) Step 2
    strSubString = Mid(input,i,2)
    if Not strSubString = "00" Then
       strPath = strPath & ChrW("&H" & strSubString)
    end If
  next
  select Case True
  case InStr(strPath,":\") > 0
    GetPath = Mid(strPath,InStr(strPath,":\")-1)
  case InStr(strPath,"\\") > 0
    GetPath = Mid(strPath,InStr(strPath,"\\"))
  end Select
end Function