39 заметок с тегом

windows

Позднее Ctrl + ↑

Используем WinDbg для поиска причины падения w3wp.exe

Выкатили свежее веб приложение, которое себя отлично вело на предпродакшн серверах, а оно начало «крашить» w3wp.exe. Пытались «оддебажить» Debug Diagnostic Tool v2.0, но никаких результатов вменяемых мы не получили. И вот в один прекрасный день я наткнулся на замечательную статью и уже из нее узнал о существовании WinDbg. Дальнейший поиск вывел меня на еще одну статью.
IIS складывает дампы в папку c:\ProgramData\Microsoft\Windows\WER\ReportQueue\ и там уже AppCrash_w3wp.exe_<некий хеш> в которой находятся файлы, например:

WER87FF.tmp.dmp
WER4CC3.tmp.hdmp
WER4C63.tmp.appcompat.txt
Report.wer
WER4CB2.tmp.WERInternalMetadata.xml

Для отладки запускаем установленную WinDbg и дальше Ctrl+D (File — Open crash Dump...) и указываем файл с расширением .hdmp.
Открывшийся дамп предстает перед нами в таком виде:

Подгружаем SOS модули для .NET
Для .NET 2.0 | 3.0 | 3.5

.loadby sos mscorwks

Для .NET 4.0

.loadby sos clr

Для вывода Stack Trace вводим команду:

!clrstack

и получаем вывод типа:

Для вывода потоков вводим команду:

!threads

и получаем список потоков:

В этом списке потоков я обнаружил строку:

129    9  e08 000000554889dba0  1029220 Preemptive  000000507063E940:0000005070640758 00000055488f41c0 1     MTA (Threadpool Worker) System.StackOverflowException 0000004cb0501188 (nested exceptions)

Вот он тот самый «эксепшн» StackOverflow который мы и искали.
«Открываем» нужный нам поток командой:

~129s

А теперь смотрим что у него внутри:

!clrstack

и начинаем анализировать вывод:

Скачать WinDbg

WinDbg 6.12.0002.633 (x64)
WinDbg 6.12.0002.633 (x86)

 14   2014   iis   windows

Миграция роли Active Directory и перенос контроллера домена на другой сервер

Как недавно выяснилось, процесс миграции домена с Windows Server 2003 на Windows Server 2008/R2 (либо просто на другой сервер) для начинающих системных администраторов представляет сложности и даже вызывает некоторую боязнь, хотя на самом деле он настолько прост, что о написании такой статьи я даже и не задумывался никогда, тем более что в интернете их полно.

Тем не менее, целью данной статьи было объединить типовые действия, возникающие при миграции, поэтому приступим. Статья будет представлять собой пошаговый мануал, с наиболее распространенным случаем миграции с 2003 на 2008 R2 и с необходимыми отступлениями для других вариантов.
Собственно шаги:

  • Исходные данные и техзадание,
  • Подготовительные работы,
  • Обновление схемы леса и домена,
  • Передача ролей FSMO,
  • Перенос глобального каталога,
  • Перенастройка интерфейсов, DNS и другие послеустановочные задачи.

Исходные данные и техзадание

Исходная ситуация — существует домен, testcompany.local. Для упрощения в нем будет один контроллер домена под Windows Server 2003, с именем dc01. DNS-сервер также на нем, основная зона интегрирована в Active Directory.

Сетевые настройки контроллера:

IP-адрес — 192.168.1.11
Маска — 255.255.255.0
Шлюз — 192.168.1.1
DNS-сервер — 192.168.1.11

Задача — установить контроллер домена на другом сервере, причем работающем под Windows Server 2008 R2, старый контроллер понизить до рядового сервера (а затем возможно, удалить вообще), а все функции старого контроллера передать новому.

Подготовительные работы

В качестве подготовительных работ следует запустить команды netdiag (эта команда существует только в 2003 Server, Support Tools) и dcdiag, убедиться в отсутствии ошибок, а при их наличии исправить эти ошибки.
В первую очередь определяем держателя FSMO-ролей в домене, командой:

netdom query fsmo

Утилита netdom.exe в состав Windows Server 2003 по умолчанию не входит, поэтому нужно установить Support Tools. В рассматриваемом случае от нее смысла никакого нет, так как контроллер домена всего один и роли FSMO все равно все на нем. Тем же, у кого контроллеров домена больше одного, это будет полезно, чтобы знать, какие именно роли и откуда переносить. Результат команды будет примерно таким:

Далее, устанавливаем операционную систему Windows Server 2008 R2 на новый сервер, даем имя dc02, задаем сетевые настройки:

IP-адрес — 192.168.1.12
Маска — 255.255.255.0
Шлюз — 192.168.1.1
DNS-сервер — 192.168.1.11

и вводим его в существующий домен, testcompany.local в нашем случае.

Обновление схемы леса и домена

Следующий этап — обновление схемы леса и домена до Windows Server 2008 R2, что мы будем делать с помощью утилиты adprep. Вставляем установочный диск с Windows Server 2008 R2 в сервер dc01. На диске нас интересует папка X:\support\adprep (X: — буква диска DVD-ROM). Если windows Server 2003 у вас 32-х битная, следует запускать запускать adprep32.exe, в случае 64-х битной — adprep.exe.

Для выполнения команды adprep /forestprep никаких требований к функциональному режиму леса нет. Для выполнения команды adprep /domainprep требуется, чтобы в домене использовался функциональный уровень домена не ниже Windows 2000 native.
Вводим команду:

X:\support\adprep>adprep32.exe /forestprep

После предупреждения о том, что все контроллеры домена Windows 2000 должны быть минимум с SP4 вводим С и нажимаем Enter:

Команда отрабатывает довольно долго, несколько минут и должна завершиться следующей фразой:

Adprep successfully updated the forest-wide information.

После этого вводим команду:

X:\support\adprep>adprep32.exe /domainprep /gpprep

Которая отработает не в пример быстрее:

Также стоит выполнить команду adprep /rodcprep. Даже если вы и не собираетесь использовать в вашей сети контроллеры домена только для чтения (Read Only Domain Controller — RODC), эта команда как минимум уберет ненужные сообщения об ошибках в журнале событий.

После завершения действия команд по обновлению схемы можно приступать к повышению роли нового сервера до контроллера домена.

На сервере dc02 заходим в Server Manager, добавляем роль Active Directory Domain Services. После установки роли, зайдя в Server Manager > Roles > Active Directory Domain Services, мы увидим желтую подсказку «Run the Active Directory Domain Services Installation Wizard (dcpromo.exe)». Ее и запускаем. Либо можно в командной строке набрать dcpromo, что будет равноценно вышеприведенному действию.

Так как освещение процесса установки контроллера домена в эту статью не входит, остановлюсь лишь на некоторых ключевых моментах. На шаге Additional Domain Controller Options поставьте обе галки, DNS Server и Global catalog.

Если галку Global Catalog и DNS Server не поставить, придется их переносить отдельно. А при миграции с 2003 на 2003 это придется делать в любом случае, так как в Windows 2003 такой возможности (установки DNS-сервера и глобального каталога при добавлении добавочного контроллера домена) нет. О переносе глобального каталога и DNS-сервера будет немного ниже.

Завершаем установку контроллера домена, перезагружаем сервер. Теперь у нас есть два контроллера домена, работающих одновременно.

Передача ролей FSMO

Передачу ролей FSMO можно производить как через графический интерфейс, так и с помощью утилиты ntdsutil.exe. В этой статье будет описан способ с использованием графического интерфейса, как более наглядный, кого интересует другой способ, он по этой ссылке: http://support.microsoft.com/kb/255504.
Передача ролей FSMO будет состоять из следующих шагов:

  • Передача роли Schema Master,
  • Передача роли Domain Naming Master,
  • Передача ролей RID Master, PDC Emulator и Infrastructure Master.

Передача роли Schema Master

Заходим на сервер dc02, на тот, на который будем передавать роли. Для того, чтобы получить доступ к оснастке Active Directory Schema, сначала необходимо зарегистрировать библиотеку schmmgmt.dll. Это делается с помощью команды:

regsvr32 schmmgmt.dll

Далее, Start > Run > mmc > Enter. В окне оснастки находим и добавляем компонент Active Directory Schema.

В дереве оснастки нужно щелкнуть правой кнопкой мыши элемент Active Directory Schema и выбрать пункт Change Domain Controller. Там меняем контроллер на dc02.
Далее опять нажимаем правой кнопкой мыши элемент Active Directory Schema и выбираем пункт Operations Master. Появляется вот такое окно:

Нажимаем Change > Yes > OK и закрываем все эти окна.

Передача роли Domain Naming Master

Открываем оснастку Active Directory Domains and Trusts, щелкаем правой кнопкой мыши элемент Active Directory Domains and Trusts и выбираем команду Change Active Directory Domain Controller. Это действие необходимо, если работа ведется не с контроллера домена, которому передается роль. Пропустите его, если подключение к контроллеру домена, чья роль передается, уже установлено. В открывшемся окне выбираем контроллер домена, которому присваивается роль (dc02 в нашем случае), в списке и нажимаем кнопку ОК.

В оснастке щелкаем правой кнопкой мыши элемент Active Directory Domains and Trusts и выбираем пункт Operations Master. В появившемся окне нажимаем кнопку Change.

Чтобы подтвердить передачу роли, нажимаем кнопку ОК, а затем — Close.

Передача ролей RID Master, PDC Emulator и Infrastructure Master

Открываем оснастку Active Directory Users and Computers. Щелкаем правой кнопкой мыши элемент Active Directory Users and Computers и выбираем команду Change Domain Controller. Пропустите его, если подключение к контроллеру домена, чья роль передается, уже установлено. В открывшемся окне выбираем контроллер домена, которому присваивается роль (dc02 в нашем случае), в списке и нажимаем кнопку ОК.

В оснастке щелкаем правой кнопкой мыши элемент Active Directory Users and Computers, выбираем пункт All Tasks, а затем Operations Master.

Выбираем вкладку, соответствующую передаваемой роли (RID, PDC или Infrastructure Master), и нажимаем кнопку Change. Чтобы подтвердить передачу роли, нажимаем кнопку ОК, а затем — Close.

Перенос глобального каталога

Если мы делаем миграцию не на 2008, а на 2003, в котором при добавлении добавочного контроллера домена глобальный каталог не ставится, либо вы не поставили галку Global Catalog при установке добавочного контроллера домена, тогда нужно назначить роль глобального каталога новому контроллеру домена вручную. Для этого, заходим в оснастку Active Directory Sites and Services, раскрываем Sites > сайт Default-First-Site-Name > Servers > DC02 > щелкаем правой кнопкой мыши по NTDS Settings > Properties. В открывшемся окне ставим галку Global Catalog > OK.

После этого, в логах Directory Service появится сообщение, что повышение роли контроллера до глобального каталога будет отложено на 5 минут:

Event Type: Information
Event Source: NTDS General
Event Category: (18)
Event ID: 1110
Date: 12.07.2011
Time: 22:49:31
User: TESTCOMPANY\Administrator
Computer: dc02.testcompany.local
Description:
Promotion of this domain controller to a global catalog will be delayed for the following interval.

Interval (minutes):
5

This delay is necessary so that the required directory partitions can be prepared before the global catalog is advertised. In the registry, you can specify the number of seconds that the directory system agent will wait before promoting the local domain controller to a global catalog. For more information about the Global Catalog Delay Advertisement registry value, see the Resource Kit Distributed Systems Guide.

Ждем пять минут и дожидаемся события 1119 о том, что этот контроллер стал глобальным каталогом:

Event Type: Information
Event Source: NTDS General
Event Category: (18)
Event ID: 1119
Date: 12.07.2011
Time: 22:54:31
User: NT AUTHORITY\ANONYMOUS LOGON
Computer: dc02.testcompany.local
Description:
This domain controller is now a global catalog.

Перенастройка интерфейсов, DNS и другие послеустановочные задачи

Далее, так как DNS-сервер на dc02 мы установили, теперь нужно в свойствах сетевого интерфейса первичным DNS-сервером указать самого себя, т. е. адрес 192.168.1.12. И на dc01 соответственно поменять на 192.168.1.12.

В свойствах DNS-сервера на dc02 проверьте вкладку Forwarders, на 2003, в отличие от 2008, она не реплицируется. После этого можно понижать контроллер домена dc01 до рядового сервера.

Если вам необходимо у нового контроллера оставить старое имя и IP-адрес, то это также делается без проблем. Имя меняется как для обычного компьютера, либо командой netdom renamecomputer.

После смены IP-адреса выполните команды ipconfig /registerdns и dcdiag /fix.

Использованные источники:
http://support.microsoft.com/kb/324801
http://technet.microsoft.com/en-us/library/cc731728(WS.10).aspx
http://technet.microsoft.com/ru-ru/library/upgrade-domain-controllers-to-windows-server-2008-r2(WS.10).aspx#BKMK_FL

(c) sysadminz.ru

 10   2014   ad   windows

URL Rewrite some.domain.com to domain.com/some

Как в IIS прописать правило URL Rewrite для перенаправления (rewrite) some.domain.com в domain.com/some?
Решение:

<rule name="CName to URL" stopProcessing="true">
    <match url=".*" />
    <conditions>
        <add input="{HTTP_HOST}" pattern="^(?!www)(.*)\.domain\.com$" />
    </conditions>
    <action type="Redirect" url="http://domain.com/{C:1}/{R:0}" />
</rule>

Этим правилом мы перенаправляем http://some.domain.com на http://domain.com/some. Оно так же поддерживает запросы, например, http://some.domain.com/aboutus?more=info перенаправит на http://domain.com/some/aboutus?more=info.

То же самое можно сделать применив перезапись (rewrite):

<rule name="CName to URL - Rewrite" stopProcessing="true">
    <match url=".*" />
    <conditions>
        <add input="{HTTP_HOST}" pattern="^(?!www)(.*)\.domain\.com$" />
    </conditions>
    <action type="Rewrite" url="/{C:1}/{R:0}" />
</rule>

Для посетителя запрос будет выглядеть как http://some.domain.com/aboutus/, а для сервера это будет запрос в папку /some/aboutus/.

 6   2014   iis   web   windows

Создание персональных папок для пользователей домена

Простенький скрипт, точнее три его разновидности, для случая, когда необходимо создать папки для ряда пользователей на файловом сервере при условии, что названия папок будут совпадать с именами пользователей и эти пользователи будут иметь определенный уровень доступа к этим (своим) папкам. Все это может создаваться внутри определенной папки непосредственно на сервере или через сеть в общей папке по UNC пути.

Первый пример использует дополнительный модуль ActiveDirectory и предназначен для случая, когда пользователи находятся в каком-либо OU в AD:

#
# PowerShell Script.
# Creates home folders for users from an OU in AD and set permissions.
# Prepared by Alexander Lipovetskiy. August 2013.
#

cls

# We need the AD module for this first
Import-Module ActiveDirectory

# A folder or share where home folders must be created.
$Dir = "D:\Users"
# or $Dir = "\\server\share\"

# Path to an OU with users.
$Users = Get-ADUser -Filter * -SearchBase "OU=Users,OU=Muhosransk,DC=domain,DC=com"

# Creating folders and setting permissions.
foreach ($User in $Users) {
    $User = $User.Name
    $Path = New-Item -ItemType Directory -Path $Dir -Name $User
    $Args = New-Object  system.security.accesscontrol.filesystemaccessrule($User,"Modify, Synchronize", "ContainerInherit, ObjectInherit", "None", "Allow")
    $ACL = Get-Acl $Path
    $ACL.SetAccessRule($Args)
    Set-Acl $Path $ACL
    }

Второй пример обрабатывает список пользователей, находящийся в текстовом файле:

#
# PowerShell Script.
# Creates home folders for a list of users and set permissions.
# Prepared by Alexander Lipovetskiy. August 2013.
#

cls

# A folder or share where home folders must be created.
$Dir = "D:\Users"
# or $Dir = "\\server\share\"

# Path to a text file with users.
$Users = Get-Content "$home\users.txt"

# Creating folders and setting permissions.
foreach ($User in $Users) {
    $Path = New-Item -ItemType Directory -Path $Dir -Name $User
    $Args = New-Object  system.security.accesscontrol.filesystemaccessrule($User,"Modify, Synchronize", "ContainerInherit, ObjectInherit", "None", "Allow")
    $ACL = Get-Acl $Path
    $ACL.SetAccessRule($Args)
    Set-Acl $Path $ACL
    }

В данных примерах устанавливаются не полные права, а «Modify, Synchronize» не дающие возможности пользователям менять security permissions и становиться владельцами папок. Конечно все это можно поменять на FullControl или что-либо другое. Также в примерах установлено наследование разрешений подпапками и файлами.

Третий пример, для случая, когда папки создаются для членов АД группы и прописываются им как домашние директории:

#
# PowerShell Script.
# Creates home folders for a list of users and set permissions.
# Prepared by Alexander Lipovetskiy. August 2013.
#

cls

# We need the AD module for this first
Import-Module ActiveDirectory

# A folder or share where home folders must be created.
$Dir = "D:\Users"
# or $Dir = "\\server\share\"

# Extract group members.
$Users = Get-ADGroupMember -Identity "Groupname" -Recursive

# Creating folders and setting permissions.
foreach ($User in $Users) {
    $Path = New-Item -ItemType Directory -Path $Dir -Name $User
    $Args = New-Object  system.security.accesscontrol.filesystemaccessrule($User,"Modify, Synchronize", "ContainerInherit, ObjectInherit", "None", "Allow")
    $ACL = Get-Acl $Path
    $ACL.SetAccessRule($Args)
    Set-Acl $Path $ACL
    Set-ADUser -Identity $User -HomeDrive "Z:" -HomeDirectory "$Dir$User"
    }

habrahabr.ru

 11   2013   windows

Переносим Windows системы из физической в виртуальную среду

Практически каждый раз, когда я рассказываю о виртуализации, люди задают один и тот же вопрос. Как переносить все то, что нажито непосильным трудом в систему виртуализации? Не хочется ведь настраивать все заново.

Обычно я рекомендую несколько вариантов:
Воспользоваться SCVMM и обязательно прочитать вот эту статью о миграции P2V и посмотреть вебкаст о миграции в SCVMM

Применить для миграции VSMT и ADSк

Взять на вооружение инструменты третьих фирм, такие как Paragon Vitalization Manager или Acronis True Image Echo Server

Сегодня у нас появился еще один бесплатный способ сделать то, что нужно, играючи. Компания Sysinternals, ныне входящая в состав Microsoft, выпустила утилиту disk2vhd, которая позволяет конвертировать Windows системы в VHD файлы, не прерывая их работы. Поддерживаются все клиентские и серверные системы, начиная с Windows XP SP2 и Windows Server 2003. Затем VHD файлы можно подключить к системам виртуализации, таким как Hyper-V, Virtual Server или Virtual PC и запустить перенесенные системы. Работает это проще простого. Скачиваем утилиту disk2vhd или запускаем disk2vhd прямо из интернет в той системе, которую собираемся мигрировать. Выбираем, какие разделы конвертировать в vhd, и, если есть необходимость, продолжаем работать в системе, ожидая завершения процесса.

Я решил конвертировать в VHD только раздел MAIN, находящийся на первом физическом диске моей системы. Именно с него загружается система и на нем стоят все нужные приложения.

Процесс конвертации системного раздела Windows 7 занял примерно 40 минут. Вероятно, это случилось потому, что результирующий VHD файл писался на медленный внешний USB накопитель. Во время работы disk2vhd я писал эту заметку и работал с другими приложениями в мигрируемой системе. Каких-либо неудобств замечено не было. Для ускорения процесса рекомендуется записывать получившийся VHD на диск, не участвующий в конвертировании.

После получения VHD диска копируем его в систему виртуализации и создаем новую виртуальную машину. Подсоединяем к ней наш VHD, настраиваем нужные параметры, такие как виртуальная память, и количество сетевых интерфейсов.

Сразу же после первого запуска на новом месте, из виртуальной машины автоматически удаляются все ненужные физические устройства и устанавливаются все необходимые виртуальные. Перезагрузите виртуальную машину и наслаждайтесь результатом.

Обратите внимание, что расположение NTFS раздела MAIN, который мы переносили, абсолютно точно скопировано в виртуальный VHD. Совпадает все вплоть до неразмеченного места, на которое при желании можно расширить NTFS раздел MAIN.

Единственной проблемой, которую я заметил, является несовпадение Windows Experience Index реальной системе и невозможность его пересчитать в виртуальной. Думаю, что это не критично.

Как видите, ничего сложного в процессе переноса работающих ОС в системы виртуализации от Microsoft нет.

Удачных вам проектов миграции!
Andrey Beshkov

 13   2013   hyper-v   windows

Полезные скрипты T-SQL

Много различных T-SQL скриптов

что сейчас происходит на сервере

select session_id, status, wait_type, command, last_wait_type, percent_complete, qt.text, total_elapsed_time/1000 as [total_elapsed_time, сек],
       wait_time/1000 as [wait_time, сек], (total_elapsed_time - wait_time)/1000 as [work_time, сек]
  from sys.dm_exec_requests as qs
  CROSS APPLY sys.dm_exec_sql_text(qs.sql_handle) as qt
  where session_id >= 50 and session_id <> @@spid
  order by 1;

что сейчас происходит на сервере (подробнее)

select *
  from sys.sysprocesses where spid > 50 and spid <> @@spid and status <> 'sleeping'
  order by spid, ecid;

фрагментированные индексы

SELECT TOP 100
       DatbaseName = DB_NAME(),
       TableName = OBJECT_NAME(s.[object_id]),
       IndexName = i.name,
       i.type_desc,
       [Fragmentation %] = ROUND(avg_fragmentation_in_percent,2),
       page_count,
       partition_number,
       'alter index [' + i.name + '] on [' + sh.name + '].['+ OBJECT_NAME(s.[object_id]) + '] REBUILD' + case
                                                                                                           when p.data_space_id is not null then ' PARTITION = '+convert(varchar(100),partition_number)
                                                                                                           else ''
                                                                                                         end + ' with(maxdop = 1,  SORT_IN_TEMPDB = on)' [sql]
  FROM sys.dm_db_index_physical_stats(db_id(),null, null, null, null) s
  INNER JOIN sys.indexes as i ON s.[object_id] = i.[object_id] AND
                                 s.index_id = i.index_id
  left join sys.partition_schemes as p on i.data_space_id = p.data_space_id
  left join sys.objects o on  s.[object_id] = o.[object_id]
  left join sys.schemas as sh on sh.[schema_id] = o.[schema_id]
  WHERE s.database_id = DB_ID() AND
        i.name IS NOT NULL AND
        OBJECTPROPERTY(s.[object_id], 'IsMsShipped') = 0 and
        page_count > 100 and
        avg_fragmentation_in_percent > 10
  ORDER BY 4,page_count;

задержки

SELECT TOP 10
 [Wait type] = wait_type,
 [Wait time (s)] = wait_time_ms / 1000,
 [% waiting] = CONVERT(DECIMAL(12,2), wait_time_ms * 100.0 
               / SUM(wait_time_ms) OVER())
  FROM sys.dm_os_wait_stats
  WHERE wait_type NOT LIKE '%SLEEP%' 
  ORDER BY wait_time_ms DESC;

итоговое число отсутствующих индексов для каждой базы данных

SELECT [DatabaseName] = DB_NAME(database_id),
       [Number Indexes Missing] = count(*) 
  FROM sys.dm_db_missing_index_details
  GROUP BY DB_NAME(database_id)
  ORDER BY 2 DESC;

Отсутствующие индексы, вызывающие издержки

SELECT TOP 10 
       [Total Cost] = ROUND(avg_total_user_cost * avg_user_impact * (user_seeks + user_scans),0),
       avg_user_impact,
       TableName = statement,
       [EqualityUsage] = equality_columns,
       [InequalityUsage] = inequality_columns,
       [Include Cloumns] = included_columns
  FROM sys.dm_db_missing_index_groups g 
  INNER JOIN sys.dm_db_missing_index_group_stats s ON s.group_handle = g.index_group_handle 
  INNER JOIN sys.dm_db_missing_index_details d ON d.index_handle = g.index_handle
  WHERE database_id = DB_ID()
  ORDER BY [Total Cost] DESC;

Неиспользуемые индексы

SELECT DatabaseName = DB_NAME(),
       TableName = OBJECT_NAME(s.[object_id]),
       IndexName = i.name,
       user_updates,
       system_updates,
       'EXEC sp_rename ''[dbo].['+OBJECT_NAME(s.[object_id])+'].['+i.name+']'',''disable_'+i.name+''',''INDEX''' as Rename,
       'ALTER INDEX '+i.name+' ON '+OBJECT_NAME(s.[object_id])+' DISABLE' as [Disable]
  FROM sys.dm_db_index_usage_stats s 
  INNER JOIN sys.indexes i ON s.[object_id] = i.[object_id] AND
                              s.index_id = i.index_id
  WHERE s.database_id = DB_ID() AND
        OBJECTPROPERTY(s.[object_id], 'IsMsShipped') = 0 AND
        user_seeks = 0     AND
        user_scans = 0     AND
        user_lookups = 0   AND
        i.is_disabled <> 1 AND
        i.is_primary_key <> 1
  order by user_updates + system_updates desc;

Запросы с высокими издержками на ввод-вывод

SELECT TOP 10
       [Average IO] = (total_logical_reads + total_logical_writes) / qs.execution_count,
       [Total IO] = (total_logical_reads + total_logical_writes),
       [Execution count] = qs.execution_count,
       [Individual Query] = SUBSTRING (qt.text,qs.statement_start_offset/2, (CASE
                                                                               WHEN qs.statement_end_offset = -1 THEN LEN(CONVERT(NVARCHAR(MAX), qt.text)) * 2 
                                                                               ELSE qs.statement_end_offset
                                                                             END - qs.statement_start_offset)/2),
       [Parent Query] = qt.text,
       [DatabaseName] = DB_NAME(qt.dbid)
  FROM sys.dm_exec_query_stats qs
  CROSS APPLY sys.dm_exec_sql_text(qs.sql_handle) as qt
  ORDER BY [Average IO] DESC;

Запросы с высоким использованием ресурсов ЦП

SELECT TOP 10
       [Average CPU used] = total_worker_time / qs.execution_count,
       [Total CPU used] = total_worker_time,
       [Execution count] = qs.execution_count,
       [Individual Query] = SUBSTRING(qt.text,qs.statement_start_offset/2, 
         (CASE
            WHEN qs.statement_end_offset = -1 THEN LEN(CONVERT(NVARCHAR(MAX), qt.text)) * 2 
            ELSE qs.statement_end_offset
          END - qs.statement_start_offset)/2),
       [Parent Query] = qt.text,
       [DatabaseName] = DB_NAME(qt.dbid)
  FROM sys.dm_exec_query_stats qs
  CROSS APPLY sys.dm_exec_sql_text(qs.sql_handle) as qt
  ORDER BY [Average CPU used] DESC;

Запросы, страдающие от блокировки

SELECT TOP 10
       [Average Time Blocked] = (total_elapsed_time - total_worker_time) / qs.execution_count,
       [Total Time Blocked] = total_elapsed_time - total_worker_time,
       [Execution count] = qs.execution_count,
       [Individual Query] = SUBSTRING (qt.text,qs.statement_start_offset/2, 
         (CASE
            WHEN qs.statement_end_offset = -1 THEN LEN(CONVERT(NVARCHAR(MAX), qt.text)) * 2 
            ELSE qs.statement_end_offset
          END - qs.statement_start_offset)/2),
       [Parent Query] = qt.text,
       [DatabaseName] = DB_NAME(qt.dbid)
  FROM sys.dm_exec_query_stats qs
  CROSS APPLY sys.dm_exec_sql_text(qs.sql_handle) as qt
  ORDER BY [Average Time Blocked] DESC;

нагрузку на подсистему ввода-вывода

select top 5 
    (total_logical_reads/execution_count) as avg_logical_reads,
    (total_logical_writes/execution_count) as avg_logical_writes,
    (total_physical_reads/execution_count) as avg_phys_reads,
     Execution_count, 
    statement_start_offset as stmt_start_offset, 
    plan_handle,
    qt.text
from sys.dm_exec_query_stats  qs
CROSS APPLY sys.dm_exec_sql_text(qs.sql_handle) as qt
order by  (total_logical_reads + total_logical_writes) Desc;

какой процессор что делает

SELECT DB_NAME(ISNULL(s.dbid,1)) AS [Имя базы данных],
       c.session_id AS [ID сессии],
       t.scheduler_id AS [Номер процессора],
       s.text AS [Текст SQL-запроса]
  FROM sys.dm_exec_connections AS c
  CROSS APPLY master.sys.dm_exec_sql_text(c.most_recent_sql_handle) AS s
  JOIN sys.dm_os_tasks t ON t.session_id = c.session_id AND
                            t.task_state = 'RUNNING' AND
                            ISNULL(s.dbid,1) > 4
  ORDER BY c.session_id DESC;

контроль «несжатости»

SELECT tbl.name,
       i.name,
       p.partition_number AS [PartitionNumber],
       p.data_compression_desc AS [DataCompression],
       p.rows  AS [RowCount]
  FROM sys.tables AS tbl
  LEFT JOIN sys.indexes AS i ON (i.index_id > 0 and i.is_hypothetical = 0) AND (i.object_id=tbl.object_id)
  INNER JOIN sys.partitions AS p ON p.object_id = CAST(tbl.object_id AS int) AND
                                    p.index_id = CAST(i.index_id AS int)
  where p.data_compression_desc <> 'PAGE' and
        p.rows >= 1000000
  order by p.rows desc, 3;

статистика по операциям в БД

SELECT t.name AS [TableName],
       fi.page_count AS [Pages],
       fi.record_count AS [Rows],
       CAST(fi.avg_record_size_in_bytes AS int) AS [AverageRecordBytes],
       CAST(fi.avg_fragmentation_in_percent AS int) AS [AverageFragmentationPercent],
       SUM(iop.leaf_insert_count) AS [Inserts],
       SUM(iop.leaf_delete_count) AS [Deletes],
       SUM(iop.leaf_update_count) AS [Updates],
       SUM(iop.row_lock_count) AS [RowLocks],
       SUM(iop.page_lock_count) AS [PageLocks]
  FROM sys.dm_db_index_operational_stats(DB_ID(),NULL,NULL,NULL) AS iop
  JOIN sys.indexes AS i ON iop.index_id = i.index_id AND
                           iop.object_id = i.object_id
  JOIN sys.tables AS t ON i.object_id = t.object_id AND
                          i.type_desc IN ('CLUSTERED', 'HEAP')
  JOIN sys.dm_db_index_physical_stats(DB_ID(), NULL, NULL, NULL, 'SAMPLED') AS fi ON fi.object_id=CAST(t.object_id AS int) AND
                                                                                     fi.index_id=CAST(i.index_id AS int)
  GROUP BY t.name, fi.page_count, fi.record_count, fi.avg_record_size_in_bytes, fi.avg_fragmentation_in_percent
  ORDER BY [RowLocks] desc;

дата обновления статистики

SELECT STATS_DATE(t1.object_id, stats_id), 'UPDATE STATISTICS [' + object_name(t1.object_id) + ']([' + t1.name + ']) WITH FULLSCAN',
       i1.rows
  FROM sys.stats as t1
  inner join sys.sysobjects as t2 on t1.object_id = t2.id
  left join sysindexes as i1 on i1.id = t1.object_id and
                                i1.indid = 1
  where xtype = 'U' and
        STATS_DATE(t1.object_id, stats_id) < GETDATE()-5 and
        -- не учитываем: мусор, постоянные данные, таблицы на удаление
        t1.name not like 'disable%' and
        object_name(t1.object_id) not like '[__]%' and
        object_name(t1.object_id) not like 'T[_]%' and
        object_name(t1.object_id) not like 'OSMP%' and
        -- исключаем автостатистику,
        -- она создана по ad-hoc запросам, поэтому не является необходимой
        -- во время ночных расчетов
         t1.name not like '[_]WA[_]Sys[_]%'
  order by STATS_DATE(t1.object_id, stats_id);

i/o-нагрузка на файлы

SELECT TOP 10 DB_NAME(saf.dbid) AS [База данных],
       saf.name AS [Логическое имя],
       vfs.BytesRead/1048576 AS [Прочитано (Мб)],
       vfs.BytesWritten/1048576 AS [Записано (Мб)],
       saf.filename AS [Путь к файлу]
  FROM master..sysaltfiles AS saf
  JOIN ::fn_virtualfilestats(NULL,NULL) AS vfs ON vfs.dbid = saf.dbid AND
                                                  vfs.fileid = saf.fileid AND
                                                  saf.dbid NOT IN (1,3,4)
  ORDER BY vfs.BytesRead/1048576 + BytesWritten/1048576 DESC;

i/o-нагрузка на диски

SELECT SUBSTRING(saf.physical_name, 1, 1)    AS [Диск],
       SUM(vfs.num_of_bytes_read/1048576)    AS [Прочитано (Мб)],
       SUM(vfs.num_of_bytes_written/1048576) AS [Записано (Мб)]
  FROM sys.master_files AS saf
  JOIN sys.dm_io_virtual_file_stats(NULL,NULL) AS vfs ON vfs.database_id = saf.database_id AND
                                                         vfs.file_id = saf.file_id AND
                                                         saf.database_id NOT IN (1,3,4) AND
                                                         saf.type < 2
  GROUP BY SUBSTRING(saf.physical_name, 1, 1)
  ORDER BY [Диск];

Занимаемое на диске место

SELECT TOP 1000
       (row_number() over(order by (a1.reserved + ISNULL(a4.reserved,0)) desc))%2 as l1,
       a3.name AS [schemaname],
       a2.name AS [tablename],
       a1.rows as row_count,
      (a1.reserved + ISNULL(a4.reserved,0))* 8 AS reserved,
       a1.data * 8 AS data,
      (CASE WHEN (a1.used + ISNULL(a4.used,0)) > a1.data THEN (a1.used + ISNULL(a4.used,0)) - a1.data ELSE 0 END) * 8 AS index_size,
      (CASE WHEN (a1.reserved + ISNULL(a4.reserved,0)) > a1.used THEN (a1.reserved + ISNULL(a4.reserved,0)) - a1.used ELSE 0 END) * 8 AS unused,
      'ALTER TABLE [' + a2.name  + '] REBUILD' as [sql]
  FROM (SELECT ps.object_id,
               SUM(CASE WHEN (ps.index_id < 2) THEN row_count ELSE 0 END) AS [rows],
               SUM(ps.reserved_page_count) AS reserved,
               SUM(CASE WHEN (ps.index_id < 2) THEN (ps.in_row_data_page_count + ps.lob_used_page_count + ps.row_overflow_used_page_count) ELSE (ps.lob_used_page_count + ps.row_overflow_used_page_count) END) AS data,
               SUM(ps.used_page_count) AS used
          FROM sys.dm_db_partition_stats ps
          GROUP BY ps.object_id
       ) AS a1
  LEFT JOIN (SELECT it.parent_id,
                    SUM(ps.reserved_page_count) AS reserved,
                    SUM(ps.used_page_count) AS used
               FROM sys.dm_db_partition_stats ps
               INNER JOIN sys.internal_tables it ON (it.object_id = ps.object_id)
               WHERE it.internal_type IN (202,204)
               GROUP BY it.parent_id
            ) AS a4 ON (a4.parent_id = a1.object_id)
  INNER JOIN sys.all_objects a2  ON ( a1.object_id = a2.object_id )
  INNER JOIN sys.schemas a3 ON (a2.schema_id = a3.schema_id)
  WHERE a2.type <> N'S' and a2.type <> N'IT'
  ORDER BY 8 DESC;

под какие объекты выделена память

select count(*)as cached_pages_count,
       obj.name as objectname,
       ind.name as indexname,
       obj.index_id as indexid
  from sys.dm_os_buffer_descriptors as bd
  inner join (select object_id as objectid,
                     object_name(object_id) as name,
                     index_id,allocation_unit_id
                from sys.allocation_units as au
                inner join sys.partitions as p on au.container_id = p.hobt_id and (au.type = 1 or au.type = 3)
                union all
                select object_id as objectid,
                       object_name(object_id) as name,
                       index_id,allocation_unit_id
                  from sys.allocation_units as au
                  inner join sys.partitions as p on au.container_id = p.partition_id and au.type = 2
             ) as obj on bd.allocation_unit_id = obj.allocation_unit_id
  left outer join sys.indexes ind on obj.objectid = ind.object_id and
                                     obj.index_id = ind.index_id
  where bd.database_id = db_id() and
        bd.page_type in ('data_page', 'index_page')
  group by obj.name, ind.name, obj.index_id
  order by cached_pages_count desc;
 11   2013   sql   windows

Windows Vista/7/Server 2008. Не удается загрузить C:\Windows\System32\iprtrmgr.dll

Настраивал маршрутизацию под 2008 r2 сервером и в перед запуском службы получил Windows Vista/7/Server 2008. Не удается загрузить C:\Windows\System32\iprtrmgr.dll.
Необходимо отключить протокол IPv6. В зависимости от ситуации решения разные.

В большинстве случаев для отключения поддержки IPv6 следуем указаниям статьи «Отключение некоторых компонентов протокола IP версии 6 в Windows Vista, Windows 7 и Windows Server 2008» из базы знаний Microsoft. (предпочтительней).

Если ошибка связана с настройкой маршрутизации и удалённого доступа на Windows Server 2008:

Имя журнала:   System
Источник:      RemoteAccess
Дата:          12.09.2011 16:29:53
Код события:   20103
Категория задачи:Отсутствует
Уровень:       Ошибка
Ключевые слова:Классический
Пользователь:  Н/Д
Компьютер:     SERVER.domain.ru
Описание:
Не удается загрузить C:\Windows\System32\iprtrmgr.dll.
Xml события:
<Event xmlns="http://schemas.microsoft.com/win/2004/08/events/event">
  <System>
    <Provider Name="RemoteAccess" />
    <EventID Qualifiers="0">20103</EventID>
    <Level>2</Level>
    <Task>0</Task>
    <Keywords>0x80000000000000</Keywords>
    <TimeCreated SystemTime="2011-09-12T12:29:53.000000000Z" />
    <EventRecordID>10950</EventRecordID>
    <Channel>System</Channel>
    <Computer>SERVER.domain.ru</Computer>
    <Security />
  </System>
  <EventData>
    <Data>C:\Windows\System32\iprtrmgr.dll</Data>
    <Binary>1F000000</Binary>
  </EventData>
</Event>

то следует удалить ветку реестра HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Services\RemoteAccess\RouterManagers\Ipv6:

reg delete "HKLM\SYSTEM\CurrentControlSet\Services\RemoteAccess\RouterManagers\Ipv6" /f

и перезапустить службу «Маршрутизация и удалённый доступ»:

net stop RemoteAccess
net start RemoteAccess
 12   2013   windows

Уменьшение размера базы данных tempdb в SQL Server

В данной статье приведены три способа, которые можно использовать для уменьшения размера базы данных tempdb до значения, которое будет меньше последнего заданного размера.
Первый способ предоставляет полный контроль над размером файлов базы данных tempdb, но требует перезапуска сервера SQL Server.
Второй способ позволяет уменьшить размер базы данных tempdb в целом с некоторыми ограничениями, которые могут потребовать перезапуска сервера SQL Server.
Третий способ позволяет уменьшить размер отдельных файлов базы данных tempdb.
Последние два способа требуют, чтобы в процессе операции уменьшения размера с базой данных tempdb не производилось никаких действий.

 23   2013   sql   windows

Invalid object name ’tempdb.dbo.ASPStateTempApplications’

Если вы используете IIS совместно с базой ASPState и в одно прекрасное утро видите в браузере ошибку Invalid object name ’tempdb.dbo.ASPStateTempApplications’, то на SQL сервере нужно выполнить следующий скрипт:

USE [ASPState]
GO
DECLARE @return_value int
EXEC @return_value = [dbo].[CreateTempTables]
SELECT 'Return Value' = @return_value
GO
 6   2013   iis   windows

PowerShell: Синхронизация с помощью robocopy

Про замечательную утилу robocopy я уже писал в заметке Перенос MDaemon на другой сервер, но тогда я использовал консоль, сейчас же мне потребовалось использовать PoerShell. Что бы не изобретать велосипед я полез искать, т. к. решения просто обязаны быть.
Был найден скрипт за авторством NIKLAS JUMLIN. Скрипт запускает robocopy с параметрами и ведет логи.

## This Script Mirrors a directory tree from source to destination with the Windows builtin command robocopy.
## Exit codes from robocopy are logged to Windows Eventlog.
## Author: NIKLAS JUMLIN

## Usage: Run with administrative rights in Windows Task Scheduler or Administrator:PowerShell
## If not executed with administrative privileges the script will not write to eventlog.

## Change these parameters
## ================================================================

## Name of the job, name of source in Windows Event Log and name of robocopy Logfile.
$JOB = "DB Backup"

## Source directory
$SOURCE = "C:\Base"

## Destination directory. Files in this directory will mirror the source directory. Extra files will be deleted!
$DESTINATION = "E:\Backup"

## Path to robocopy logfile
$LOGFILE = "E:\Backup\LOGS\$JOB"

## Log events from the script to this location
$SCRIPTLOG = "E:\Backup\LOGS\$JOB.log"

## Mirror a direcotory tree
$WHAT = @("/MIR")
## /COPY:DATS: Copy Data, Attributes, Timestamps, Security
## /SECFIX : FIX file SECurity on all files, even skipped files.

## Retry open files 3 times wait 30 seconds between tries. 
$OPTIONS = @("/R:3","/W:30","/NDL","/NFL")
## /NFL : No File List - don't log file names.
## /NDL : No Directory List - don't log directory names.
## /L   : List only - don't copy, timestamp or delete any files.

## This will create a timestamp like yyyy-mm-yy
$TIMESTAMP = get-date -uformat "%Y-%m%-%d"

## This will get the time like HH:MM:SS
$TIME = get-date -uformat "%T"

## Append to robocopy logfile with timestamp
$ROBOCOPYLOG = "/LOG+:$LOGFILE`-$TIMESTAMP.log"

## Wrap all above arguments
$cmdArgs = @("$SOURCE","$DESTINATION",$WHAT,$ROBOCOPYLOG,$OPTIONS)

## ================================================================

## Start the robocopy with above parameters and log errors in Windows Eventlog.
&amp; C:\Windows\System32\Robocopy.exe @cmdArgs

## Get LastExitCode and store in variable
$ExitCode = $LastExitCode

$MSGType=@{
"16"="Errror"
"8"="Error"
"4"="Warning"
"2"="Information"
"1"="Information"
"0"="Information"
}

## Message descriptions for each ExitCode.
$MSG=@{
"16"="Serious error. robocopy did not copy any files.`n
Examine the output log: $LOGFILE`-Robocopy`-$TIMESTAMP.log"
"8"="Some files or directories could not be copied (copy errors occurred and the retry limit was exceeded).`n
Check these errors further: $LOGFILE`-Robocopy`-$TIMESTAMP.log"
"4"="Some Mismatched files or directories were detected.`n
Examine the output log: $LOGFILE`-Robocopy`-$TIMESTAMP.log.`
Housekeeping is probably necessary."
"2"="Some Extra files or directories were detected and removed in $DESTINATION.`n
Check the output log for details: $LOGFILE`-Robocopy`-$TIMESTAMP.log"
"1"="New files from $SOURCE copied to $DESTINATION.`n
Check the output log for details: $LOGFILE`-Robocopy`-$TIMESTAMP.log"
"0"="$SOURCE and $DESTINATION in sync. No files copied.`n
Check the output log for details: $LOGFILE`-Robocopy`-$TIMESTAMP.log"
}

## Function to see if running with administrator privileges
function Test-Administrator  
{  
    $user = [Security.Principal.WindowsIdentity]::GetCurrent();
    (New-Object Security.Principal.WindowsPrincipal $user).IsInRole([Security.Principal.WindowsBuiltinRole]::Administrator)  
}

## If running with administrator privileges
If (Test-Administrator -eq $True) {
	"Has administrator privileges"

	## Create EventLog Source if not already exists
	if ([System.Diagnostics.EventLog]::SourceExists("$JOB") -eq $false) {
	"Creating EventLog Source `"$JOB`""
    [System.Diagnostics.EventLog]::CreateEventSource("$JOB", "Application")
	}

	## Write known ExitCodes to EventLog
	if ($MSG."$ExitCode" -gt $null) {
		Write-EventLog -LogName Application -Source $JOB -EventID $ExitCode -EntryType $MSGType."$ExitCode" -Message $MSG."$ExitCode"
	}
	## Write unknown ExitCodes to EventLog
	else {
		Write-EventLog -LogName Application -Source $JOB -EventID $ExitCode -EntryType Warning -Message "Unknown ExitCode. EventID equals ExitCode"
	}
}
## If not running with administrator privileges
else {
	## Write to screen and logfile
	Add-content $SCRIPTLOG "$TIMESTAMP $TIME No administrator privileges" -PassThru
	Add-content $SCRIPTLOG "$TIMESTAMP $TIME Cannot write to EventLog" -PassThru

	## Write known ExitCodes to screen and logfile
	if ($MSG."$ExitCode" -gt $null) {
		Add-content $SCRIPTLOG "$TIMESTAMP $TIME Printing message to logfile:" -PassThru
		Add-content $SCRIPTLOG ($TIMESTAMP + ' ' + $TIME + ' ' + $MSG."$ExitCode") -PassThru
		Add-content $SCRIPTLOG "$TIMESTAMP $TIME ExitCode`=$ExitCode" -PassThru
	}
	## Write unknown ExitCodes to screen and logfile
	else {
		Add-content $SCRIPTLOG "$TIMESTAMP $TIME ExitCode`=$ExitCode (UNKNOWN)" -PassThru
	}
	Add-content $SCRIPTLOG ""
	Return
}
 10   2013   windows
Ранее Ctrl + ↓