Показаны сообщения с ярлыком Scripting. Показать все сообщения
Показаны сообщения с ярлыком Scripting. Показать все сообщения

вторник, 22 ноября 2011 г.

Сколько проживет SSD

Немного провокационный заголовок, не так ли? На самом деле я не собираюсь тут приводить процедуру расчета времени жизни SSD. Хочу написать о другом. Сегодня коллега задал вопрос: “Есть ли счетчик, который помог бы определить, сколько данных записано на диск. И вообще, как определить количество данных, записанных на диск?”. Собственно тут хотел бы привести свое видение ответа, так сказать.
Как оказалось – нет в perfmon такого счетчика. Ну, нет и все тут. Вероятно, есть на то какие-то причины. Но интересующие данные, судя по всему, получить таки можно. На ответ наткнулся совсем случайно. Для того чтобы получить нужные цифры можно воспользоваться утилитой fsutil. А конкретно, командой, например fsutil fsinfo statistics g: Утилита возвращает кучу всего, и, в частности значение UserFileWriteBytes, которое, похоже, и показывает нужную информацию. Стоит отметить, что эти данные, видимо, сбрасываются при перезагрузке. Ну и в качестве тренировки написал скрипт, который парсит все это счастье и возвращает хэш-таблицу с нужными данными:
function Get-DiskStats ($diskLetter){
 if (Test-Path $diskLetter) {
    (fsutil fsinfo statistics $diskLetter) | `
    where {$_.length -ne 0} | `
    %{$_.replace(" ","")} | `
    % {$_ -match "(?\w+):(?[0-9]{1,})"; $matches} | `
    % {$ret = @{}} {$ret["$($_.name)"]=$_.value}
    return $ret}
 else {Write-Error "There is no disk $diskLetter"; return $null}
}

Get-DiskStats g:

Подозреваю правда, что информацию можно получить так же при помощи ETW. Вот только как – не углублялся пока. PS. Некоторые изменения к плану. Если вы хотите собрать данные с работающего сервера за некоторый промежуток времени - вы можете поступить следующим образом.
1. Получить статистику на начальный момент времени:
Get-DiskStats c: | Export-Clixml c:\Files\disk.xml
Этим самым вы сохраните начальные данные в файл xml.
2. На конечный момент можно поступить следующим образом:
$old = Import-Clixml c:\Files\disk.xml
$new = Get-DiskStats c:


$old.Keys | ? {$old[$_] -ne $new[$_]} | % {$obj = New-Object -TypeName psobject;
             $obj | Add-Member -MemberType NoteProperty -Name name -Value $_;
             $obj | Add-Member -MemberType NoteProperty -Name oldValue -Value $old[$_];
             $obj | Add-Member -MemberType NoteProperty -Name newValue -Value $new[$_];
             $obj} `
             | sort name | ft -AutoSize
Что вернет вам таблицу со сравнениями старых и новых значений. Вот, примерно такую:
name                oldValue   newValue   
----                --------   --------   
BitmapReadBytes     12632064   12673024   
BitmapReads         534        544        
BitmapWriteBytes    134942720  143458304  
BitmapWrites        28034      29936      
LogFileWriteBytes   1601335296 1709424640 
LogFileWrites       214884     230697     

среда, 10 августа 2011 г.

Копипаст в виртуалку

В процессе работы понадобилось передать содержимое всяких текстовых файликов в виртуалки на основе hyperv. При этом очень хотелось не подключать их ни к общей сети ни к сети компьютера-хоста. В общем – без всяких там RDP и иже с ними. Просто скопировать и вставить. Для этих целей есть встроенная возможность:

typeText

Однако если попытаться вставить большой объем текста – получается следующее:typeTextErr


Собственно говоря, покопавшись в гуглах я обнаружил, что есть WMI Классы для работы с hyperv. Собственно на основе их родилась вот такая вот функция. Особенность функции в том, что тот метод, который зовется из WMI, принимает на вход только ascii строку – 7 бит. А значит, русский шрифт, как не прискорбно, передать не выйдет. Ну да и черт с ним, хотя, конечно, печалька.

К слову говоря, sleep тут нужен по причине того, что без него работает с некоторыми странностями.
<#
.SYNOPSIS
Отправка текста в буфере обмена в виртуальную машину hyper-v

.DESCRIPTION
Текст, находящийся в буфере обмена отправляется в виртуальную машину
методом TypeText wmi класса Msvm_Keyboard. Попросту говоря при передаче текста
внутри виртуальной машины эмулируется нажатие соответствующих клавиш.
Для использования функции необходимо наличие в буфере обмена текста, и открытое активное
окно редактора текста в виртуальной машине

.PARAMETER $VM
Имя виртуальной машины.

.PARAMETER $Server
Имя hyper-v сервера. Поумолчанию используется текущая машина

.EXAMPLE
PS C:\>send-clipboardtext -vm pkidemosubordinateca1

Пример вызова функции

.INPUTS
System.String,System.String
#>
function send-clipboardText {
[CmdletBinding()]
param(
[parameter(Position=0 , Mandatory = $true, ValueFromPipeline = $false)] $VM,
[String]$Server="."
)
begin {
try {
}
catch {
}
}
process {
try {
$text = ([System.Windows.Forms.Clipboard]::GetText()) -split "`n"
$ascii = [System.Text.Encoding]::ASCII

if ($VM -is [String]) {$VM=(Get-VM -Name $VM -Server $Server) }
if ($VM -is [System.Management.ManagementObject]) {
$VSMKB=($VM.getRelated("Msvm_Keyboard") | select-object)
if ($text -ne $null ) {
foreach ($line in $text){
$bytes = $ascii.getBytes($line)
$line = $ascii.getString($bytes)
$result = $VSMKB.TypeText($line)
if ($result.returnvalue -eq 0) {write-host "'$line' was successfully sent to $vm on $server"}
sleep -Milliseconds ($line.Length*10)
}
}
}
}
catch {
echo "oops!"
$Error
}
}
end {
try {
}
catch {
}
}
}

Ну и пример вызова
send-clipboardtext -vm contosoca1

суббота, 29 января 2011 г.

За двумя зайцами.

И зачем я вечно влезаю во всякие споры на политические темы? Ведь это глупо! Вот и сегодня, влез в дискуссию на тему того что власть в России сама устраивает себе теракты с какой-то целью. Собственно говоря я не придерживаюсь такого мнения. Считаю это бредом. Но, между тем – влезаю. Так вот, коллега, в доказательство своей точки зрения прислал мне ссылку на сайт terror99.ru. Специально не делаю HREF с надеждой не дать им лишних очков в поисковиках Улыбка. Значит, прислали мне эту ссылку. Стоит иметь ввиду, что я во всем сомневаюсь. Если у кого-то есть некое мнение, то мне обязательно надо найти контраргумент. Опять же – глупо это, но часто ничего не могу с собой сделать. Вот точно так же и тут. Посмотрел я на этот сайт. Полез в about. Увидел там, что сайт создан при поддержке неких граней.ру. Никогда там не был до этого момента и в дальнейшем не пойду. Погуглил про эти самые грани. Оказалось – рупор либерастов. Новодворских всяких. Уже это заронило некую тень сомнения в адекватности этого ресурса. Кроме того натолкнулся на мнение, что грани эти спонсирует небезызвестный Березовский. Что тоже немного наводит на мысль. Далее, я поводил жалом мышью по страничке со ссылками. И у меня появилось стойкое ощущение, что большинство ссылок там ведут на эти самые грани. Поменьше – на другие либеральные издания. А на общие издания так – сверху пара ссылок, может, насыпана. И несомненно основной комок сами знаете чего на вентилятор набрасывают эти самые грани. Но ведь это надо как-то доказать! Никак ведь, без доказательств. И вот тут мне пришла в голову идея. Разобрать страницу со ссылками, и посмотреть, куда ведет большинство из них. Вот тут, собственно, я и убил второго зайца. Правда времени потратил много, ну да ничего.

Итого: я написал для этой задачки скрипт на powershell. Скрипт запрашивает страницу, выбирает из нее ссылки и рисует графичек. Для этогоя использовал MS Chart и COM объект Internet Explorer. Немного помучиться пришлось. Кроме того, я не вникал глубоко в устройство MS Chart, просто добился рабочего скрипта. Итак, скрипт:

cls

[void][Reflection.Assembly]::LoadWithPartialName("System.Windows.Forms")
[void][Reflection.Assembly]::LoadWithPartialName("System.Windows.Forms.DataVisualization")

[array]$hostnames = @()
[array]$chartData = @()
$count = 0

#тип данных для хранения информации о ссылках
Add-Type @'
public class chartDataEntry
{
public string key;
public int value;
public int percentVal;

}
'@

# создаем объект InternetExplorer.Application и запрашиваем страницу
$ie = new-object -com "InternetExplorer.Application"
$ie.navigate("http://terror99.ru/links.htm")
Start-Sleep -Milliseconds 2000 #волшебное число.ждем загрузки страницы
# разбираем страницу. достаем массив ссылок и выбираем только имена хостов
$doc = $ie.document
foreach ($link in $doc.links){
$hostnames += [string]$link.hostname
$count += 1
}

#формируем хэш-таблицу и подсчитываем
#сколько раз встречается один и тот же хост
$hostnames | % {$h=@{}} {$h[$_] += 1}

$ie.Quit() #если выйти раньше, проwесс IE не закроется

#заполняем массив данными по количеству ссылок и процентами
foreach ($item in $h.Keys){
[chartDataEntry] $entry = New-Object chartDataEntry
$entry.key = $item;
$entry.value = $h[$item];
$entry.percentVal = [int](($h[$item] / $count) * 100);
$chartData+=$entry
}

$Chart = $null
$Form = $null

# создание объекта Chart
$Chart = New-object System.Windows.Forms.DataVisualization.Charting.Chart
$Chart.Width = 1024
$Chart.Height = 768
$Chart.BackColor= [System.Drawing.Color]::Transparent

# создание области для вывода объекта Chart
$ChartArea = New-Object System.Windows.Forms.DataVisualization.Charting.ChartArea
$ChartArea.AxisX.Interval=1
$Chart.ChartAreas.Add($ChartArea)

# привязка к данным и настройка отображения
$Chart.DataBindTable($chartData,'key')
$Chart.Series[0].ChartType = [System.Windows.Forms.DataVisualization.Charting.SeriesChartType]::Bar
$Chart.Series[1].ChartType = [System.Windows.Forms.DataVisualization.Charting.SeriesChartType]::Bar
$Chart.Series[0]["DrawingStyle"]=$Chart.Series[1]["DrawingStyle"]="Cylinder"
$Chart.Series[1].IsValueShownAsLabel = $true

# легенда
$Chart.Series[0].LegendText="Кол-во ссылок"
$Chart.Series[1].LegendText="Процентное кол-во ссылок"
$chart.Legends.Add("Default")

# отображение на форме
$Chart.Anchor = [System.Windows.Forms.AnchorStyles]::Bottom -bor [System.Windows.Forms.AnchorStyles]::Right -bor
[System.Windows.Forms.AnchorStyles]::Top -bor [System.Windows.Forms.AnchorStyles]::Left


$Form = New-Object Windows.Forms.Form
$Form.Text = "PowerShell Chart"
$Form.Width = 1024
$Form.Height = 768
$Form.controls.add($Chart)
$Form.Add_Shown({$Form.Activate()})
$Form.ShowDialog()

Все расписано в комментариях. И что же в итоге? А вот что:


links


Действительно – 30% ведет на грани (олд + сами грани), 9% сам на себя, еще 9% – НТВ, лента.ру и новая газета еще 7 и 6% соответственно. В общем, набор источников информации достаточно однобок. Выводы, я думаю, каждый сделает свои. Но как по мне – бред это все!

воскресенье, 23 января 2011 г.

Непонятный TrustedHosts

На днях мой коллега задал мне вопрос, на который я не смог ответить с ходу. Ему не удавалось подключиться, с помощью powershell remoting, к удаленному серверу, находящемуся в другом домене. При попытке сделать это он получал примерно вот такое сообщение

Не удалось подключиться к удаленному серверу. Сообщение об ошибке: Клиенту WinRM не удается обработать запрос. Проверку подлинности по умолчанию можно использовать с IP-адресом при следующ
их условиях: транспортом является HTTPS или назначением является список TrustedHosts, кроме того, должны быть предоставлены явно указанные учетные данные. Чтобы настроить TrustedHosts, используйте winrm.
cmd. Обратите внимание, что в списке TrustedHosts могут находиться компьютеры, не прошедшие проверку подлинности. Для получения сведений о настройке TrustedHosts используйте следующую команду: winrm help
config. Дополнительные сведения см. в разделе справки, вызываемом командой about_Remote_Troubleshooting.

Я, в свою очередь, тоже попробовал сделать это в разных окружениях и получил несколько разных результатов:

Если клиент не входит в домен

IP Address

После нескольких экспериментов мой коллега сообщил, что если добавить адрес удаленного сервера в TrustedHosts на клиентской машине, то все работает. Все довольно странно и запутано. По этому – давайте подробнее разберем все эти ситуации.

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

  • компьютеры сервера и клиента расположены в разных доменах
  • компьютер сервера расположен в домене а клиент – вне домена
  • компьютеры сервера и клиента не входят в домен

Кроме того, исходя из сообщений об ошибках (да, их надо читать внимательно), и, соответственно, из методов обращения к серверу, есть две ситуации:

  • при обращении к серверу, клиент указывает IP-адрес в качестве адреса назначения
  • при обращении к серверу, клиент указывает имя в качестве адреса назначения

К сожалению в интернетах нет однозначного мнения по поводу того, где, на сервере или клиенте, нужно задавать параметр TrustedHosts, и нужно ли это вообще делать. На что это влияет и все такое. В целом, информация довольно скудная по этому поводу. Поэтому, после долгого забега по гуглу, я решил обратиться, куда бы вы думали – да, к первоисточнику. А именно – к спецификации на ws-management.  Про параметр TrustedHosts там сказано следующее:

TrustedHosts: Contains host names to which the Web Services Management Protocol Extensions for Windows Vista clients are allowed to send requests by using an authentication scheme and transport that does not allow the client to authenticate the service, such as Basic over HTTP.

The specified host names may be either Internet host names or IP addresses. TrustedHosts

  • Blank: No hosts are trusted.
  • The asterisk "*" character: All hosts are trusted.
  • A list of host name patterns separated by the comma "," character, in which each host name can be one of four possible values:
    • String starting with the asterisk "*" character and containing at least two characters. All hosts that share the suffix are trusted.
    • String ending with the asterisk "*" character and containing at least two characters. All hosts that share the prefix are trusted.
    • The exact string "": All NetBIOS names are trusted (for example, strings that do not contain the period "." character).
    • A string without the asterisk "*" character: The host named by the string is trusted.

The default value for the <TrustedHosts> element MUST be a blank string.

Основная идея выделена. И это означает, что параметр TrustedHosts нужно использовать на клиенте. В этом списке указываются машины, при работе с которыми невозможно использовать схемы с поддержкой взаимной аутентификации. Таким образом, если и клиент и сервер находятся в одном домене, то для подключения вы можете использовать простую команду без дополнительных параметров.

Следующий этап – два домена с доверительными отношениями. В этом случае тоже нет необходимости в TrustedHosts. Однако необходимо обеспечить корректное разрешение имен. Однако, скажете вы, ведь в домене можно обращаться не только по имени, а еще и по адресу, и все должно работать корректно. А у нас, при попытке использовать адрес, вываливается ошибка. И вот тут возникает необходимость внимательно прочитать содержимое ошибки:

Проверку подлинности по умолчанию можно использовать с IP-адресом при следующих условиях: Транспортом является HTTPS или назначением является список TrustedHosts.

Прежде всего видим, что в TrustedHosts нужно указывать именно назначение. А почему такое ограничение на использование IP-адреса? Об этом написано в блоге Ask the Directory Services Team. Вкратце, там сказано, что нельзя в качестве использовать IP-адреса в синтаксисе записи SPN. И если в windows xp/2003 это работало то в Vista и старше при использовании IP-адреса в назначении не будет даже попыток использовать kerberos . Отсюда и ошибка: раз не используется протокол с взаимной аутентификацией – используйте HTTPS или пропишите TrustedHosts. Для того чтобы убедиться в этом, вы можете воспользоваться вашим любимым сниффером. В нем вы увидите, что клиент даже не пытается установить связь с сервером, если вы указываете в качестве назначения адрес. Ошибка выдается сразу. Более подробно про SPN вы можете так же прочесть в моей статье.

И наконец – не доменное окружение. Powershell знает, что клиентская машина не в домене. Значит kerberos по определению не возможен. Следовательно либо TrustedHosts либо HTTPS.

среда, 12 января 2011 г.

Powershell и Exchange 5.5

Эта тема коснулась меня в свете миграции почтовых ящиков с Exchange 5.5 на Exchange 2003. Какой ужас, скажете вы, на дворе ведь 2011 год. К огромному моему сожалению это реальность. В то время как космические корабли бороздят … Большой театр, мы переезжаем с Exchange 5.5 на Exchange 2003.  Поэтому в дальнейшем я буду писать “старый” и “новый” сервер. Именно в кавычках. Мда. Но вместе с тем, к делу.

Процедура переезда достаточно простая. На текущем этапе просто происходит миграция ящиков. Пользователи пока остаются в старом домене, но, за счет доверительных отношений имеют доступ к новым ящикам. Однако, есть проблема. Когда пользователи “старого” сервера отправляют почту, используя свою адресную книгу, тем, кто уже переехал, возникает странная ситуация. Почта вроде бы отправилась, но у конечного абонента ее нет. Как тут быть? Решение вроде бы простое. Нужно создать контакт, который будет указывать на новый адрес в “новом” сервере. А затем подключить этот контакт как альтернативного получателя к тому почтовому ящику, чей пользователь уже на “новом” сервере. И все бы хорошо, но вот проблема – пользователей много, и создавать эти контакты вручную очень долго и нудно. Как тут быть? На помощь приходит, как ни странно, powershell и немного смекалки.

Exchange 5.5 поддерживает свой LDAP сервер и каталог, к которому можно добраться при помощи стандартных механизмов. Кроме того можно экспортировать и импортировать каталог в файл. Этим и воспользуемся. Прежде всего я экспортировал все почтовые ящики в один и одного контакта в другой csv файл. Затем, при помощи excel скопировал нужные данные из первого файла во второй так, чтобы при импорте файла с контактами получить эти контакты сразу в скрытом виде. В частности нужно изменить поле Directory Name, чтобы оно не совпадало с Directory Name у ящика. Ну, и импортировал полученный файл в отдельный контейнер под названием newDomainContainer. Осталось связать почтовые ящики и новые альтернативные контакты. Как выяснилось, для этого достаточно добавить к записи ящика атрибут "Alt-Recipient".

Что делаем.

$strLdapUser = "cn=administrator,dc=domain,cn=admin"
$strLdapPass = "password"

$mailRecipients = Get-Content c:\temp\exchange2.csv

foreach ($str in $mailRecipients){
$params = $str.split(",") #разделяем строку на куски
if ($params[5] -ne "Directory Name"){ #пропускаем заголовок 
$path = "LDAP://mailserver/cn="+$params[4]+",cn=Recipients,ou=domain,o=org"
$recipient = New-Object DirectoryServices.DirectoryEntry($path,$strLdapUser,$strLdapPass,0)
$recipient.Properties["Alt-Recipient"].Value = "cn="+$params[5]+",cn=newDomainContainer,cn=Recipients,ou=domain,o=org"
$recipient.CommitChanges()
$recipient.close()}
}
Скрипт не универсальный. Просто, так сказать, пруф оф концепт. На входе у него файл для импорта контактов. Поле с номером 5 – это Directory Name. Поле номер 4 - Alias Name. По нему происходит поиск в каталоге. Ну и собственно все. Для каждой строки происходит подключение к серверу и получение объекта почтового ящика. Затем у этого почтового ящика изменяется значение атрибута "Alt-Recipient". Если его изначально нет, нужно делать так:
$ds.Properties["Alt-Recipient"].Add("cn="+$params[5]+",cn=newDomainContainer,cn=Recipients,ou=domain,o=org" )
Вот. Затем CommitChanges сохраняет изменения назад.
Конечно, с точки зрения производительности тоже не лучший вариант. Само собой, что стоило вынести подключение за цикл. Но для этого нужно было бы разбираться с классами поиска. Я решил пойти более легким путем.
В общем, сомневаюсь, что кому-то пригодится, но на всякий случай пускай будет Улыбка

среда, 5 января 2011 г.

Несколько неприятных багов

Мда. Никто не без греха. Самое неприятное, что я, к примеру, доверяю тем программным компонентам, которые использую. При этом, автоматически думаю, что если что-то не получается, то проблема в конфигурации или, там, в моем понимании ситуации и тд. Однако, редко но метко, попадаются неприятные баги. Буквально пару дней назад разбирался с технологией wsman и возможностями ее использования при помощи powershell. В Windows окружении все, вроде, работает. Но при попытке использовать сервер wsman на Linux стали появляться проблемы с аутентификацией. И тут я начал грешить на то, что что-то где-то неправильно настроил. Перекопал все, мучал гугл. Всю голову себе сломал. И тут, совершенно случайно наткнулся на вот эту заметку. В ней говорится о баге в одном из компонентов библиотеки, отвечающей за реализацию набора командлетов для wsman. Это ведет за собой невозможность basic аутентификации во всех командлетах набора. Это ужасно. Примечательно, что и в microsoft об этом уже сообщено и бага эта уже давнешняя, заметка датирована сентябрем 2009 года, а воз и ныне там. Ужасно.
Не представляю, что бы я делал, если бы не нашел этой заметки. Наверное до сих пор грешил бы на неверную конфигурацию.
PS. Уважаемые разработчики Microsoft, пофиксите, пожалуйста, багу!

PPS.
Вот ссылка на багу на Microsoft Connect. Огромная просьба всем, пожалуйста, голосуйте за то чтобы ее исправили. Может быть поможет?

Небольшие изменения в скрипте установки UVNC.

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

Get-QADcomputer -Name "*" | Select-Object name

Это сделано для того, чтобы не изменять основное тело скрипта.

Пожалуйста, оставляйте ваши комментарии Улыбка

понедельник, 3 января 2011 г.

Лучше поздно чем никогда.

Совершенно случайно наткнулся на эту заметку. Основная идея в том, что есть возможность при помощи reflector “дизассемблировать” содержимое командлетов powershell. Вот таким вот образом:

function Reflect-Cmdlet {  
param([Management.Automation.CommandInfo]$command)
if ($input) {
trap { $_; break }
$command = $input | select -first 1
}

# resolve to command if this is an alias
while ($command.CommandType -eq "Alias") {
$command = Get-Command ($command.definition)
}

$name = $command.ImplementingType
$DLL = $command.DLL

if (-not (gcm reflector.exe -ea silentlycontinue)) {
throw "I can't find Reflector.exe in your path."
}

reflector /select:$name $DLL
}

get-command Get-WSManInstance | Reflect-Cmdlet

Для этого вам необходимо чтобы утилита reflector находилась в PATH.

среда, 15 декабря 2010 г.

Скрипт для борьбы с kido

В общем, устал я от этой гадости. К сожалению не все антивирусы его ловят до сих пор. Кроме того, порой возникает желание зайти на машину с админскими привилегиями, что я, иногда, и делаю.  В итоге, если машина заражена даже при наличии на ней антивируса, эта штука получает нужные права и понеслась.  И выковыривай ее потом, с учетом пассивности антивирусов. Мда. В общем, решил я написать скрипт для подобной проверки с использованием утилиты kk от касперского. Удобство этого скрипта в том, что его можно звать для кучи северов и машин сразу:

"\\server1", "\\server2"  | test-kido
При этом у вас на машине появятся консольные окошки с прогрессом проверки. Для работы вам нужно положить в path утилиты psexec и kk<. И при запуске скрипта будет немного счастья.
function test-kido {
[CmdletBinding()]
param (
[parameter(Mandatory=$true,ValueFromPipeline=$true,Position=0)]
[string[]]$computername
)
PROCESS {

$util = "psexec"
$commandLine = "$computername -c -f kk -y -a -z"
Start-Process -FilePath $util -ArgumentList $commandLine
}
}

среда, 3 ноября 2010 г.

Отказоустойчивое копирование

 

Давненько ничего не писал. Все как-то не складывалось. То одно то другое. А теперь вот, появилась минутка и живое настроение Улыбка. На улице солнце светит, не жарко но и не холодно. Жизнь идет, скоро новый год. В общем – нормально. В итоге возникло желаньице написать коротенькую заметку вот по какому вопросу. Недавно захотелось мне, верней не мне а пользователям, странного – заиметь просмотрщик PDF файлов. Я предпочитаю Foxit reader. В общем, нужно было скопировать инсталляху на удаленный комп по низкоскоростному (64к), нестабильному каналу. Обычные попытки сделать это, путем копирования на административный общий ресурс на клиенте успехом не увенчались. Соединение то и дело отваливалось. Robocopy тоже не очень подходило, потому как нужно было скопировать всего один файл, а эта утилита копирует целые каталоги. В итоге я решил испытать BITS в связке с powershell: командлет start-bitstransfer. Этот механизм позволяет передавать файлы с докачкой в асинхронном режиме. То есть запустил и забыл.

cls
$job = Start-BitsTransfer -Source 'D:\Downloads\Программы\Foxit reader\FoxitReader31_enu_Setup_091125.exe' -Destination '\\client\c$\FoxitReader31_enu_Setup_091125.exe' -TransferType upload -Asynchronous

$job
Идея тут в чем. В переменную $job возвращается объект, который следит за процессом копирования. Запрашивая ее периодически можно следить за результатом. Я не следил. Спросил пару раз вначале, и когда вспомнил о том что запускал копирование – еще раз спросил Улыбка. И получил вот такой результат

 


bits

пятница, 27 августа 2010 г.

Logparser и Powershell

 

Некоторое время назад я пробовал использовать powershell для разбора больших текстовых файлов. Однако, оказалось, что это не самый быстрый способ. Утилита logparser значительно быстрей в этих вопросах. Однако, при желании, можно все таки скрестить ужа и ежа и добиться производительности, сохранив при этом удобство. Logparser предоставляет COM интерфейсы, а значит, что можно вызывать внутренний функционал этой утилиты прямо из powershell. Тут я, не мудрствуя лукаво, отошлю вас к этой статье, поскольку это не я реализовал. Однако тут приведу лишь некоторые значимые части.

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

  • LogQuery – Объект используется для выполнения запросов батчей
  • LogRecordSet – Объект, возвращаемый методом LogQuery.Execute
  • LogRecord – Объект, порожденный от LogRecordset. Объект возвращается методом LogRecordSet.getRecord

В общем, все объекты достаточно хорошо описаны в документации, есть даже пример на C#.

Сама powershell библиотечка состоит из набора функций. Я оставлю некоторые специфичные термины без перевода чтобы было понятней:

  • Get-LPInputFormat – Возвращает input format object  Log Parser’а
  • Get-LPOutputFormat – Возвращает  output format object Log Parser’а
  • Invoke-LPExecute – Выполняет или запускает метод LogQuery.Execute и возвращает LogRecordSet
  • Invoke-LPExecuteBatch – Выполняет или запускает метод LogQuery.ExecuteBatch и выводит результат в запрошенном формате
  • Get-LPRecordSet – Исполняет Log Parser Query и возвращает LogRecordSet как массив объектов Powershell
  • Get-LPRecord – Возвращает объект LogRecord object  как PowerShell object из текущего LogRecordSet object

Вот, собственно, сама библиотека:

среда, 30 июня 2010 г.

Удаленная установка UltraVNC с драйвером

Не стану говорить о том, почему мне понадобилось это сделать. Факт в том, что понадобилось. Попросту говоря, понадобилось ПО с этим функционалом, но бесплатное. После длительных размышлений выбор пал именно на UltraVNC. Попробую пояснить почему. Хотелось решение, в котором есть возможность использовать видеодрайвер, так называемый mirror driver, благодаря которому работа с решением с точки зрения клиентской машины значительно ускоряется. Проще говоря производительность сервера с драйвером раз в 5-7 выше, нежели без драйвера. А учитывая порой плачевное состояние парка машин, это условие было, пожалуй, очень важным. Драйвер такой есть у нескольких производителей. Однако RealVNC не дает его с бесплатной версией а TightVNC находится в какой-то странной бете, а я бетам не доверяю. Может быть незаслуженно, но это все таки бета.

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

среда, 10 марта 2010 г.

Windows и логи squid 2: Анализ логов squid

Следующим шагом будет небольшая модернизация нашей таблицы в sql server и самого скрипта, а так же простое и быстрое получение отчета. Наша задача быстро и просто, без лишней головной боли получить отчет по использованию трафика пользователями. Для этого мы воспользуемся таким супернавернутым средством как microsoft excel. Как оказалось, круче него только горы.

Однако, для начала нам стоит изменить таблицу sql server, в которой хранятся наши логи. Мы добавим вычисляемое поле, которое будет преобразовывать данные объемов трафика из байтов в мегабайты. Для этого можно сделать примерно следующее:

alter table accesslog add mb as ((cast ([size] as decimal (20,3))/1024)/1024)

Проблема в том, что поле size у нас типа bigint, что обусловлено типом в файле лога. Верней особенностями logparser при работе с типами. При создании вычисляемого поля, сервер использует тип данных для поля, основываясь на исходных полях. В итоге, если не использовать преобразование cast ([size] as decimal (20,3) тип данных нового поля будет целым, что приведет к потере дробной части.

После добавления поля, количество полей, понятное дело, изменится. Это требует небольшой коррекции скрипта:

LogParser.exe" -o:sql -server:SQLSERVER -database:weblog -ignoreIdCols:on -createTable:on -i:TSV -iSeparator:space -nSep:1 -headerRow:off "select TO_TIMESTAMP( ADD( TO_INT(field1), TO_INT(TIMESTAMP('1970','yyyy')) ) ) AS field1, field2, field3, field4, field5, field6, field7, field8, field9, field10, 0.0 into accesslog from \\gateway\squid\access.log.2"

Нужно добавить в конце инструкции select еще одно поле подходящего типа. Это, опять же, требования самого logparser.

Итак, предварительные приготовления сделаны. Займемся отчетом. Займет эта процедура очень немного времени. На самом деле значительно меньше, чем у меня ушло на написание этой заметки.

Прежде всего создаем источник данных, путем создания запроса к внешним данным:

olap1

 olap2

Указываем параметры нового запроса. А именно, откуда берем данные: сервер, таблица, язык. Язык влияет на формат дат. Кроме того выбираем тип аутентификации на сервере. В моем случае это доменная аутентификация. Однако можно использовать и аутентификацию sql server.

olap3

olap4

olap6

Теперь, используя вновь созданный источник, начинаем выбирать данные.

olap5

Тут нам нужно выбрать все поля таблицы, в которой хранятся данные squid, которые мы импортировали нашим скриптом. Для этого вам будет предложено окошко визарда. Прежде всего там нужно выбрать поля фактов. То есть поля, по которым будет происходить агрегирование. В нашем случае мы выбираем ранее созданное поле mb – объем данных, преобразованых к мегабайтам.

olap7

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

oplap8

Затем визард предложит вам выбрать тип создаваемого куба. Я выбрал тут первый тип, чтобы не ждать долго его создания.

olap9

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

olap12

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

В общем и целом – задача довольно простая. Результат выглядит удобно и достаточно интерактивен, поскольку можно строить всякие графички, плюшечки и всякие разные красивости при помощи того же excel.

понедельник, 8 марта 2010 г.

Windows и логи squid

  Некоторое время назад потребовалось предоставлять информацию, на предмет использования интернет на рабочем месте. Вообще, я считаю, что это лишнее. Если люди делают свою работу хорошо, зачем ограничивать им интернет. Тем более что в наше время он совсем не дорог. Однако руководство имеет совсем другое мнение. Заковыка состояла в том, что вся инфраструктура построена на windows, а прокси, соответственно, на linux. Файлы логов опубликованы на этом linux при помощи общей папки. Однако, имеющиеся под linux средства анализа и генерации отчетов никого не устроили по непонятным мне причинам. Вероятно потому, что внешний вид отчетов оставляет желать лучшего. Да и работать c html отчетами не удобно. Другое средство - internet access monitor for squid почему-то вело себя совсем неадекватно. Что, учитывая его стоимость и ограничения, совсем не хорошо. Например, поставить его можно только на одно рабочее место. То есть, если несколько человек хотят посмотреть отчеты и при этом, при необходимости, детализировать их там где надо, возникает проблема. Отчеты можно генерировать по расписанию, и рассылать почтой, но вот нужного функционала нет. Мало того, при быстром разрастании базы отчеты строятся “тыщщу лет”. В общем – никакой стабильности.

    Поколебамшись, я решил накрутить что-нибудь сам. Идея была в том, чтобы втянуть логи, как есть, в MS SQL Server, и потом обрабатывать их. И вот тут то и появилась первая проблема. Логи формата по-умолчанию, никак не хотели втягиваться стандартным визардом импорта. Верней, втягиваться то они втягивались. Но визард, разбирал их не совсем корректно. А все потому, что отформатированы они, мягко говоря, через одно место. То есть, человеку их, конечно, удобно читать. А вот разобрать их на столбцы простыми кликами мышки оказалось сложнее. В итоге, я решил использовать для этой цели powershell. Дай, думаю, я удалю лишние пробелы, авось втянется. Однако и тут, облом подкрался незаметно… Время обработки одного 300мб файла переваливало за 11 мин. Меня такая ситуация не устраивала в корне.

    В общем, поборовшись, какое-то время за скорость я решил вернуться к более традиционным средствам LogParser. Оказалось, что эта утилита умеет не только исполнять простые запросы на sql подобном языке к файлам различных форматов. Она умеет еще кучу всего всякого разного, включая преобразование форматов и запись в таблицы SQL Server. Последнее его свойство я и решил попробовать использовать. Оставалась только одна задача. Поле даты в этих журналах хранится в формате unix timestamp. Соответственно его нужно преобразовать к подходящему формату. И тут на помощь снова приходит logparser. Он подерживает некий набор функций, по работе с данными входных файлов. В общем и целом, без долгих разговоров – вот такой вот простой скрипт:

LogParser.exe" -o:sql -server:SQLSERVER -database:weblog -ignoreIdCols:on -createTable:on -i:TSV -iSeparator:space -nSep:1 -headerRow:off "select TO_TIMESTAMP( ADD( TO_INT(field1), TO_INT(TIMESTAMP('1970','yyyy')) ) ) AS field1, field2, field3, field4, field5, field6, field7, field8, field9, field10 into accesslog from \\gateway\squid\access.log.2"

Этот запрос выбирает данные прямо из логов squid и пишет их в базу ms sql. При этом, в случае отсутствия нужной таблицы первый раз, она создается. Единственный эпизод, после создания имеет смысл изменить имена полей таблицы, а так же типы данных полей, хранящих количество переданых байт и затраченое время на bigint. Это стоит сделать для того, чтобы в дальнейшем упростить запросы к базе, поскольку при агрегировании этих данных может случиться переполнение. Этот скрипт можно запускать по расписанию, допустим, каждый день. Запрос на моих объемах и условиях выполняется 5-6 минут. Думаю, процесс можно значительно ускорить, если разбить процедуру на два этапа. Сначала преобразовывать файл лога в более привычный формат, например csv, а затем втягивать его в базу при помощи bcp. Скорее всего можно достичь скорости, где-то в районе от 30 сек до минуты-двух.

суббота, 6 июня 2009 г.

SID для службы

В Windows Vista и более новых версиях ОС от Microsoft, есть довольно интересная и полезная фича – назначение SID (Security Identifier), каждому сервису отдельно. Добиться этого можно так:

sc sidtype
ОПИСАНИЕ.
        Изменение параметра типа идентификатора безопасности (SID) службы.

        Если данный параметр имеет значение unrestricted, диспетчер управления
        службами (SCM) добавит SID этой службы к маркеру процесса службы в
        следующий раз, когда этот процесс будет запущен при запуске первой из
        своих служб.  Данный параметр можно использовать только для служб
        пользовательского режима Win32.

        Если данный параметр имеет значение restricted, диспетчер управления
        службами (SCM) добавит SID этой службы к маркеру процесса службы в
        следующий раз, когда этот процесс будет запущен при запуске первой из
        своих служб. Кроме того, SID данной службы будет добавлен к списку
        ограничивающих SID в маркере процесса. Маркер процесса будет являться
        ограниченным маркером.  Дополнительные сведения об ограниченном маркере
        см. в MSDN. Данный параметр можно использовать только для служб
        пользовательского режима Win32. Кроме того, если служба является
        участником разделяемого процесса, все службы, участвующие в этом
        процессе, должны иметь данный тип SID,  чтобы описанные выше действия
        были выполнены.

        Если данный параметр имеет значение none, SCM не будет добавлять SID
        службы к маркеру процесса службы.
ИСПОЛЬЗОВАНИЕ:
        sc <сервер> sidtype [имя службы] [тип]

ПАРАМЕТРЫ:
        тип = <none|unrestricted|restricted>

То есть, вы можете указать системе, чтобы она сгенерировала специальный SID для вашей службы. К вашему сервису будет привязан SID, что даст возможность давать права на ресурсы конкретно вашей службе, и никому другому. Для этого необходимо, чтобы служба имела тип SID – unrestricted

Еще один интересный параметр – restricted. В том случае, когда он применяется, в маркер процесса, исполняющего службу, добавляется список ограничивающих SID. Например, если некий процесс выполняется с правами некоего пользователя и имеет доступ к некой папке, то если вы добавите к его маркеру ограничивающие SID, такие, что они не имеют таких прав – то и процесс, при попытке доступа в нее получит отказ. Это происходит потому, что при проверке доступа происходит две независимые проверки. Одна, для стандартного списка SID, вторая – для ограничивающего. Доступ предоставляется только в том случае, если обе проверки проходят без ошибок. По большому счету такой подход защищает систему от вашей службы, в случае, если она будет “взломана”, ведь обладая таким маркером она потеряет доступ на запись во многие места системы.

На самом деле я не большой специалист в написании скриптов :), однако вот таким вот макаром можно узнать, какие службы с каким типом SID запущен в  Vista:

cls

function sidType ($name)
{
    $si = new-object System.Diagnostics.ProcessStartInfo
    $si.FileName = "sc.exe"
    $si.CreateNoWindow = $true
    $si.RedirectStandardOutput = $true
    $si.UseShellExecute = $false
     $si.Arguments = "qsidtype " + $name

    $proc = [diagnostics.process]::Start($si)
    $proc.WaitForExit()
    [string] $str = $proc.StandardOutput.ReadToEnd().Trim().Split("`n") | Select-String -Pattern "SERVICE_SID_TYPE: "
    $str.Replace("SERVICE_SID_TYPE: ","").Trim()
};

$wmiServices = @{}
Get-WmiObject -Namespace root\cimv2 -Class Win32_Service| ForEach-Object {
    $sidType = sidType $_.Name
    $wmiServices.Add($_.Name,$sidType)
    }

$wmiServices.Keys | where-object {$wmiServices[$_] -eq "UNRESTRICTED"} | Format-Table

В результате, с типом RESTRICTED в моей системе запущены всего несколько служб:

NetTcpPortSharing
DPS
BFE
pla
MpsSvc

среда, 3 декабря 2008 г.

Отправка папки по почте.

Иногда, возникает необходимость отправить по почте большой файл или кучу маленьких. Но в нашей сети с некоторой целью, мне не всегда понятной, на вышестоящих релаях установлено ограничение на размер письма. Из-за этого большие письма не пролазят. Для того чтобы с этим справиться пришлось долго бороться с ленью и самим собой. В итоге родился следующий скрипт:


function send-folder { param ($folder, $from, $to, $server)
# $folder - путь к папке с файлами
# $from- от кого
# $to - кому
# $server - IP почтового сервера

foreach ($item in (Get-ChildItem $folder where-object {!$_.psiscontainer})) {
$mailMessage = New-Object System.Net.Mail.MailMessage ($from, $to)
$attachment = New-Object System.Net.Mail.Attachment ($item.FullName)
$mailMessage.Attachments.Add($attachment)

$client = New-Object System.Net.Mail.SmtpClient ($server)
Write-Host 'Отправка сообщения ' $item.FullName
$client.Send($mailMessage)
Write-Host 'Сообщение ' $item.FullName ' отправлено'
}
}


Этот скрипт отправляет содержимое каталога по одному файлу указанному адресату через указаный мэйл сервер.