Posts on this page:
Давненько я ничего не писал про SRP, хотя давно пора было бы заполнить некоторые пробелы. В этой статье мы разберём 3 вопроса (проблемы):
Использование SRP в 64-разрядной системе иногда чревато проблемами. Давайте разберёмся с дефолтными правилами. Их у нас всего 2:
%HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows NT\CurrentVersion\SystemRoot%
%HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows\CurrentVersion\ProgramFilesDir%
Это очень хорошие и полезные правила. Они позволяют нам запускать любые приложения из папки Windows и Program Files. Но в x64 системах у нас есть 2 класса приложений, родные x64 и унаследованные приложения x86, которые работают в режиме эмуляции. Такие приложения как правило устанавливаются в папку Program Files (x86). И если мы попробуем запустить любое приложение из папки Program Files (x86), мы получим ошибку:
Это происходит по вполне очевидным причинам. Наши правила по умолчанию не распространяются на папку Program Files (x86). Для этого мы должны создать ещё одно правило:
%HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows\CurrentVersion\ProgramFilesDir (x86)%
После этого мы сможем запускать всё из папки Program Files (x86). Вроде бы всё хорошо и замечательно. Но природа работы SRP многогранна и необычна.
Представим ситуацию, у вас установлен 32-разрядный MS Outlook (ну или любая другая 32-разрядная почтовая программа) и вам пришло письмо с приаттаченным RAR архивом. А WinRAR у вас установлен x64. Вы пытаетесь открыть архив из письма, а не получается. На сколько я проверял, вообще ничего не происходит, но в журнале событий (напоминаю, что логи SRP пишутся в журнал Application) с EventID = 865 можно найти многозначащее:
Access to C:\Program Files\WinRAR\WinRAR.exe has been restricted by your Administrator by the default software restriction policy level.
Что хотите, то и делайте. Правила все есть, а не работают. Но я не зря говорил о многогранной и необычной природе SRP. При запуске одного приложения из второго (в нашем случае из аутлука запускаем WinRAR, чтобы открыть архив) контекст SRP наследуется из родительского приложения в дочернее (если так вообще можно сказать). Если говорить простым языком, если родительское приложение (в нашем случае MS Outlook) является 32-битным, то все запускаемые из него приложения проверяются так, будто они 32-битные. На практике это означает примерно следующее. Где фактически находится ветка реестра Software для x86 приложений? Кто-то скажет, что там же, где и всегда: HKLM\Software
и будет не прав, потому что правильный ответ: HKLM\Software\Wow6432Node
. И давайте посмотрим, что нам покажут вышеперечисленные пути (из правил SRP) в реестре:
А ведут оба этих пути в одну и ту же папку, т.е. Program Files (x86). Соответственно, в такой ситуации у нас нет ни одного правила для папки Program Files и вполне логично, что WinRAR запущен не был. В обратной ситуации (когда из 64-битного аутлука запустить 32-битный WinRAR) такой проблемы нет, потому что путь в значении ProgramFiles (x86) всегда ведёт в Program Files (x86). Для решения этой проблемы в Windows 7 было добавлено ещё одно значение: ProgramW6432Dir = C:\Program Files.
Этот ключ реестра во всех случаях ведёт в папку Program Files. Следовательно, нам нужно создать ещё одно правило, которое будет включать этот параметр реестра. В сухом остатке список правил по умолчанию для x64 систем у нас должен быть минимум такой:
%HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows NT\CurrentVersion\SystemRoot%
%HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows\CurrentVersion\ProgramFilesDir%
%HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows\CurrentVersion\ProgramFilesDir (x86)%
%HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows\CurrentVersion\ProgramW6432Dir%
Эти 4 правила обеспечивают полный эквивалент правил по умолчанию, которые используются в родных x86 системах. Однако, хочу отметить один факт. Параметр ProgramW6432Dir по указанному пути присутствует только в Windows 7 и Windows Server 2008 R2. В предыдущих системах (включая Windows Vista x64 и Windows Server 2008 x64) он отсутствует. Поэтому в них для решения этой проблемы придётся прописывать абсолютные пути (без использования переменных) к папкам C:\Program Files и C:\Program Files (x86).
Достаточно часто (если исходить из общего количества внедрений SRP) администраторы наступают на одни и те же грабли. Поскольку природа терминальных серверов достаточно разнообразна, практически сложно создать какую-то одну политику SRP с правилами, которые удовлетворяли бы требованиям всех пользователей. Всегда будет так, что одному пользователю будет необходимо одно бизнес-приложение, а другому это приложение не нужно и должно быть запрещено. Адмнистраторы недолго думая пользуются тем фактом, что SRP можно настраивать и на уровне пользователя (секция User Configuration). Создают несколько политик SRP в этой секции, настраивают фильтрацию (чаще security filtering) так, чтобы каждой группе пользователей применялись нужные правила. Но сразу после применения политики могут начаться проблемы. Например, в пользовательской политике исключили расширение LNK, а на самом деле это расширение блокируется. Дело в том, что в определённых ситуациях (не скажу точно при каких условиях) SRP неявно создаёт копию политики по умолчанию в общекомпьютерной ветке реестра: HKLM\Software\Policies\Microsoft\Windows\Safer
и получается конфликт, поскольку настройки компьютерной политики (кроме правил в Additional Rules) перекрывают соответствующие настройки в пользовательской политике.
Чтобы заранее избежать подобной ситуации следует придерживаться следующего правила: создать базовую (которая применима ко всем пользователям на машине) политику в секции Computer Configuration (в этой секции определить общие настройки и глобальные правила). Для расширения прав и/или назначения гранулированных прав запуска тех или иных приложений можно назначать правила в секции User Confgiration.
Ещё давным-давно (в декабре 2007) вышла в свет Windows Vista с некоторыми изменениями в SRP. В частности правила хешей теперь поддерживают алгоритм SHA256, который не поддерживается в Windows XP и Windows Server 2003 (включая R2). Но возникает вопрос interoperability с предыдущими системами. Например, что будет, если мы создадим правило в Windows Vista, а применим его на Windows XP (через GPMC.msc, который входит в состав RSAT)?
В интернетах ходят разные мифы на этот счёт, но в реальности всё гораздо проще. Когда Windows Vista (или выше) создаёт правило хеша, система генерирует 2 хеша — родной SHA256 и совместимый хеш MD5. Таким образом обеспечивается полная совместимость с системами XP/2003. Два хеша генерируются даже если это одиночная машина в рабочей группе и совместимость с предыдущими версиями систем не требуется. Вот как это выглядит в реестре:
Здесь мы видим стандартный хеш MD5 (AlgID = 8003 это MD5). ItemData содержит фактический хеш.
Под ключом правила (каждое правило здесь указано в виде GUID'а) добавляется ещё один ключ SHA256:
Вот здесь мы видим другой идентификатор алгоритма (800c это SHA256). ItemData так же содержит фактический хеш, но не MD5, а SHA256.
Примечание: полный список криптографических алгоритмов можнно найти по здесь: http://msdn.microsoft.com/en-us/library/aa375549(VS.85).aspx
Порядок проверки хешей для XP/2003 остался тот же — только MD5. В Windows Vista сначала проверяется хеш из ключа SHA256.
Ещё давно я задался задачей автоматизировать какие-то процессы мониторинга и конфигурации серверов Enterprise CA при помощи PowerShell. Я периодически публиковал здесь отрывки своего творения (Certificate Authority, Certificates, CryptoAPI). Учитывая объём работы, я периодически забрасывал эту затею, а потом возвращался, когда этого требовала жизненная необходимость. Так же неоднократно пытался найти себе компаньона, чтобы работа двигалась быстрее. На словах — лес рук, а на деле всё пришлось делать самому (написание кода, документации и отладка). Такие дела.
В модуле я старался учесть все трудности, которые встречаются при работе с certutil'ом (в плане юзабилити) и упростить их, а так же что-то добавить из собственного опыта. Так же активно использую конвейер, что зачастую позволяет обходиться ванлайнерами. И совсем недавно я решил остановиться на разработке модуля, который был в статусе вечной преальфы и постараться выжать из сырцовчерновиков что-то логически завершённое и собрать мир,ебилдRTM. Так сказать, что-то для старта. И вот он этот старт:
>> Public Key Infrastructure PowerShell module
Пока у меня есть ещё всяких идей, которые в будущем будут добавлены в модуль. Но следует учитывать, что проект живёт, пока у меня есть желание, т.к. денег он не приносит. И однажды с ним случится то же самое, что и с овер9000 опенсурсными проектами — станет трупиком. Но это всё в будущем, а пока можно получать фан от ещё живого модуля :-)
Update 20.03.2011: исправлен синтаксис для INF
В различных интернетах ходит достаточно много слухов о правильности использования флага EDITF_ATTRIBUTESUBJECTALTNAME2. В общем смысле, администраторы включают этот флаг для выпуска сертификатов с расширением Subject Alternative Name без разбора и ссылаются на этот документ: http://support.microsoft.com/kb/931351. Но, как оказывается, мало кто осилил документ полностью.
Как видно из названия (ATTRIBUTE), этот флаг разрешает сабмитить запрос сертификата с атрибутом, содержащим расширение SAN. Этот атрибут можно добавить следующими способами:
С одной стороны, вроде, и удобно, но это сильно небезопасно. Дело в том, что если флаг EDITF_ATTRIBUTESUBJECTALTNAME2 включен, любой пользователь можешь добавить атрибут SAN к своему запросу и получить нужный сертификат, даже если шаблон не разрешает использовать расширение SAN. Данный флаг можно включать только если CA сконфгирурирован на ручное одобрение каждого запроса администратором CA, который будет следить, чтобы ни один пользователь не подсунул «левый» SAN. Но в условиях энтерпрайза это малореально. Следовательно вы НЕ ДОЛЖНЫ включать этот флаг на Enterprise CA, если он настроен на автоматическую выдачу сертификатов без премодерации!
Но мы ведь хотим SAN, но не хотим включать этот флаг. Как тогда быть? Для этого мы (и вы тоже) должны использовать один из следующих методов:
HTH
Давным давно я мечтал об удобном (ну или не очень, но чтобы стандартном) способе работы с CRL'ами в PowerShell. Ленивые разрабы .NET'а как не чесались, так и до сих пор не чешутся по этому поводу, хотя, задача весьма востребованная. Я несколько раз пытался подойти к решению этого вопроса самостоятельно. Но незнание чего-то не позволяло этого достичь. Но не так давно в качестве практического упражнения в ASN.1 я написал вот такой страшный парсер: Basic CRL parser for PowerShell. Это даже не концепт, а просто отработка навыков работы с ASN.1. Но в виду его неуниверсальности, розовомедленности его даже стыдно запускать и показывать как он работает. Неделю назад я снова вспомнил об этой теме и решил подойти к вопросу более основательно и написал код с использованием p/invoke неуправляемого кода и с блек-джеком и шлюхами, который используется стандартыми Windows инструментами для работы с CRL объектами. Я не буду рассказывать об истории его создания и как он там внутри работает, потому что это лишено всякого смысла. Взамен я предлагаю рабочий код, который вы можете использовать в собственных целях:
##################################################################### # Get-CRL.ps1 # Version 1.0 # # Retrieves CRL object from a file or a DER-encoded byte array. # # Vadims Podans (c) 2011 # http://www.sysadmins.lv/ ##################################################################### #requires -Version 2.0 function Get-CRL { <# .Synopsis Retrieves CRL object from a file or a DER-encoded byte array. .Description Retrieves CRL object from a file or a DER-encoded byte array. .Parameter Path Specifies the path to a file. .Parameter RawCRL Specifies a pointer to a DER-encoded CRL byte array. .Example Get-CRL C:\Custom.crl Returns X509CRL2 object from a specified file .Example $Raw = [IO.FILE]::ReadAllBytes("C:\Custom.crl") Get-CRL -RawCRL $Raw Returns X509CRL2 object from a DER-encoded byte array. .Outputs System.Security.Cryptography.X509Certificates.X509CRL2 .NOTES Author: Vadims Podans Blog : http://en-us.sysadmins.lv #> [OutputType('System.Security.Cryptography.X509Certificates.X509CRL2')] [CmdletBinding(DefaultParameterSetName='FileName')] param( [Parameter(ParameterSetName = "FileName", Mandatory = $true, Position = 0, ValueFromPipeline = $true)] [string]$Path, [Parameter(ParameterSetName = "RawData", Mandatory = $true, Position = 0)] [Byte[]]$RawCRL ) #region content parser switch ($PsCmdlet.ParameterSetName) { "FileName" { if ($(Get-Item $Path -ErrorAction Stop).PSProvider.Name -ne "FileSystem") { throw {"File either does not exist or not a file object"} } if ($(Get-Item $Path -ErrorAction Stop).Extension -ne ".crl") { throw {"File is not valid CRL file"} } $Content = Get-Content $Path if ($Content[0] -eq "-----BEGIN X509 CRL-----") { [Byte[]]$cBytes = [Convert]::FromBase64String($(-join $Content[1..($Content.Count - 2)])) } elseif ($Content[0][0] -eq "M") { [Byte[]]$cBytes = [Convert]::FromBase64String($(-join $Content)) } else { [Byte[]]$cBytes = [IO.File]::ReadAllBytes($Path) } } "RawData" {[Byte[]]$cBytes = $RawCRL} } #endregion $signature = @" [DllImport("CRYPT32.DLL", CharSet = CharSet.Auto, SetLastError = true)] public static extern int CertCreateCRLContext( int dwCertEncodingType, byte[] pbCrlEncoded, int cbCrlEncoded ); [DllImport("CRYPT32.DLL", SetLastError = true)] public static extern Boolean CertFreeCRLContext( IntPtr pCrlContext ); [DllImport("CRYPT32.DLL", CharSet = CharSet.Auto, SetLastError = true)] public static extern int CertNameToStr( int dwCertEncodingType, ref CRYPTOAPI_BLOB pName, int dwStrType, System.Text.StringBuilder psz, int csz ); [DllImport("CRYPT32.DLL", CharSet = CharSet.Auto, SetLastError = true)] public static extern IntPtr CertFindExtension( [MarshalAs(UnmanagedType.LPStr)]String pszObjId, int cExtensions, IntPtr rgExtensions ); [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Auto)] public struct CRL_CONTEXT { public int dwCertEncodingType; public byte[] pbCrlEncoded; public int cbCrlEncoded; public IntPtr pCrlInfo; public IntPtr hCertStore; } [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Auto)] public struct CRL_INFO { public int dwVersion; public CRYPT_ALGORITHM_IDENTIFIER SignatureAlgorithm; public CRYPTOAPI_BLOB Issuer; public Int64 ThisUpdate; public Int64 NextUpdate; public int cCRLEntry; public IntPtr rgCRLEntry; public int cExtension; public IntPtr rgExtension; } [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Auto)] public struct CRYPT_ALGORITHM_IDENTIFIER { [MarshalAs(UnmanagedType.LPStr)]public String pszObjId; public CRYPTOAPI_BLOB Parameters; } [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Auto)] public struct CRYPTOAPI_BLOB { public int cbData; public IntPtr pbData; } [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Auto)] public struct CRL_ENTRY { public CRYPTOAPI_BLOB SerialNumber; public Int64 RevocationDate; public int cExtension; public IntPtr rgExtension; } [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Auto)] public struct CERT_EXTENSION { [MarshalAs(UnmanagedType.LPStr)]public String pszObjId; public Boolean fCritical; public CRYPTOAPI_BLOB Value; } "@ Add-Type @" using System; using System.Security; using System.Security.Cryptography; using System.Security.Cryptography.X509Certificates; namespace System { namespace Security { namespace Cryptography { namespace X509Certificates { public class X509CRL2 { public int Version; public string Type; public X500DistinguishedName IssuerDN; public string Issuer; public DateTime ThisUpdate; public DateTime NextUpdate; public Oid SignatureAlgorithm; public X509ExtensionCollection Extensions; public X509CRLEntry[] RevokedCertificates; public byte[] RawData; } public class X509CRLEntry { public string SerialNumber; public DateTime RevocationDate; public int ReasonCode; public string ReasonMessage; } } } } } "@ try {Add-Type -MemberDefinition $signature -Namespace PKI -Name CRL} catch {throw "Unable to load required types"} #region Variables [IntPtr]$pvContext = [IntPtr]::Zero [IntPtr]$rgCRLEntry = [IntPtr]::Zero [IntPtr]$pByte = [IntPtr]::Zero [byte]$bByte = 0 [IntPtr]$rgExtension = [IntPtr]::Zero $ptr = [IntPtr]::Zero $Reasons = @{1="Key compromise";2="CA Compromise";3="Change of Affiliation";4="Superseded";5="Cease Of Operation"; 6="Hold Certificiate";7="Privilege Withdrawn";10="aA Compromise"} #endregion # retrive CRL context and CRL_CONTEXT structure $pvContext = [PKI.CRL]::CertCreateCRLContext(65537,$cBytes,$cBytes.Count) if ($pvContext.Equals([IntPtr]::Zero)) {throw "Unable to retrieve context"} $CRL = New-Object System.Security.Cryptography.X509Certificates.X509CRL2 # void first marshaling operation, because it throws unexpected exception try {$CRLContext = [Runtime.InteropServices.Marshal]::PtrToStructure([IntPtr]$pvContext,[PKI.CRL+CRL_CONTEXT])} catch {} $CRLContext = [Runtime.InteropServices.Marshal]::PtrToStructure([IntPtr]$pvContext,[PKI.CRL+CRL_CONTEXT]) $CRLInfo = [Runtime.InteropServices.Marshal]::PtrToStructure($CRLContext.pCrlInfo,[PKI.CRL+CRL_INFO]) $CRL.Version = $CRLInfo.dwVersion + 1 $CRL.Type = "Base CRL" $CRL.RawData = $cBytes $CRL.SignatureAlgorithm = New-Object Security.Cryptography.Oid $CRLInfo.SignatureAlgorithm.pszObjId $CRL.ThisUpdate = [datetime]::FromFileTime($CRLInfo.ThisUpdate) $CRL.NextUpdate = [datetime]::FromFileTime($CRLInfo.NextUpdate) $csz = [PKI.CRL]::CertNameToStr(65537,[ref]$CRLInfo.Issuer,3,$null,0) $psz = New-Object text.StringBuilder $csz $csz = [PKI.CRL]::CertNameToStr(65537,[ref]$CRLInfo.Issuer,3,$psz,$csz) $CRL.IssuerDN = New-Object Security.Cryptography.X509Certificates.X500DistinguishedName $psz $CRL.Issuer = $CRL.IssuerDN.Format(0) $rgCRLEntry = $CRLInfo.rgCRLEntry if ($CRLInfo.cCRLEntry -ge 1) { for ($n = 0; $n -lt $CRLInfo.cCRLEntry; $n++) { $Entry = New-Object System.Security.Cryptography.X509Certificates.X509CRLEntry $SerialNumber = "" $CRLEntry = [Runtime.InteropServices.Marshal]::PtrToStructure($rgCRLEntry,[PKI.CRL+CRL_ENTRY]) $pByte = $CRLEntry.SerialNumber.pbData $SerialNumber = "" for ($m = 0; $m -lt $CRLEntry.SerialNumber.cbData; $m++) { $bByte = [Runtime.InteropServices.Marshal]::ReadByte($pByte) $SerialNumber = "{0:x2}" -f $bByte + $SerialNumber $pByte = [int]$pByte + [Runtime.InteropServices.Marshal]::SizeOf([byte]) } $Entry.SerialNumber = $SerialNumber $Entry.RevocationDate = [datetime]::FromFileTime($CRLEntry.RevocationDate) $CRLReasonCode = "" [IntPtr]$rcExtension = [PKI.CRL]::CertFindExtension("2.5.29.21",$CRLEntry.cExtension,$CRLEntry.rgExtension) if (!$rcExtension.Equals([IntPtr]::Zero)) { $CRLExtension = [Runtime.InteropServices.Marshal]::PtrToStructure($rcExtension,[PKI.CRL+CERT_EXTENSION]) $pByte = $CRLExtension.Value.pbData $bBytes = $null for ($m = 0; $m -lt $CRLExtension.Value.cbData; $m++) { $bByte = [Runtime.InteropServices.Marshal]::ReadByte($pByte) [Byte[]]$bBytes += $bByte $pByte = [int]$pByte + [Runtime.InteropServices.Marshal]::SizeOf([byte]) } $Entry.ReasonCode = $bBytes[2] $Entry.ReasonMessage = $Reasons[$Entry.ReasonCode] } $CRL.RevokedCertificates += $Entry $rgCRLEntry = [int]$rgCRLEntry + [Runtime.InteropServices.Marshal]::SizeOf([PKI.CRL+CRL_ENTRY]) } } $rgExtension = $CRLInfo.rgExtension if ($CRLInfo.cExtension -ge 1) { $Exts = New-Object Security.Cryptography.X509Certificates.X509ExtensionCollection for ($n = 0; $n -lt $CRLInfo.cExtension; $n++) { $ExtEntry = [Runtime.InteropServices.Marshal]::PtrToStructure($rgExtension,[PKI.CRL+CERT_EXTENSION]) [IntPtr]$rgExtension = [PKI.CRL]::CertFindExtension($ExtEntry.pszObjId,$CRLInfo.cExtension,$CRLInfo.rgExtension) $pByte = $ExtEntry.Value.pbData $bBytes = $null for ($m = 0; $m -lt $ExtEntry.Value.cbData; $m++) { [byte[]]$bBytes += [Runtime.InteropServices.Marshal]::ReadByte($pByte) $pByte = [int]$pByte + [Runtime.InteropServices.Marshal]::SizeOf([byte]) } $ext = New-Object Security.Cryptography.X509Certificates.X509Extension $ExtEntry.pszObjId, @([Byte[]]$bBytes), $ExtEntry.fCritical [void]$Exts.Add($ext) $rgExtension = [int]$rgExtension + [Runtime.InteropServices.Marshal]::SizeOf([PKI.CRL+CERT_EXTENSION]) } if ($exts | ?{$_.Oid.Value -eq "2.5.29.27"}) {$CRL.Type = "Delta CRL"} $CRL.Extensions = $Exts } $CRL [void][PKI.CRL]::CertFreeCRLContext($pvContext) }
И, собственно, его вывод:
[↓] [vPodans] Get-CRL .\Desktop\pica-1.crl Version : 2 Type : Base CRL IssuerDN : System.Security.Cryptography.X509Certificates.X500DistinguishedName Issuer : CN=Sysadmins LV Internal Class 1 SubCA-1, OU=Information Systems, O=Sysadmins LV, C=LV ThisUpdate : 22.02.2011 19:22:27 NextUpdate : 26.02.2011 19:42:27 SignatureAlgorithm : System.Security.Cryptography.Oid Extensions : {System.Security.Cryptography.Oid, System.Security.Cryptography.Oid, System.Security.Cryptography .Oid, System.Security.Cryptography.Oid...} RevokedCertificates : {System.Security.Cryptography.X509Certificates.X509CRLEntry, System.Security.Cryptography.X509Cer tificates.X509CRLEntry, System.Security.Cryptography.X509Certificates.X509CRLEntry, System.Securi ty.Cryptography.X509Certificates.X509CRLEntry...} RawData : {48, 130, 3, 39...} [↓] [vPodans]
И некоторые внутренности:
[↓] [vPodans] $crl = Get-CRL .\Desktop\pica-1.crl [↓] [vPodans] $crl.Extensions[0].format(0) KeyID=1b fa 5e 73 2d 67 13 5c ce d3 0e e6 e8 7a a9 60 8c 0b 63 fc [↓] [vPodans] $crl.Extensions[4].format(1) [1]Freshest CRL Distribution Point Name: Full Name: URL=http://www.sysadmins.lv/pki/pica-1+.crl [↓] [vPodans] $crl.RevokedCertificates SerialNumber RevocationDate ReasonCode ReasonMessage ------------ -------------- ---------- ------------- 3bfe8e77000000000078 27.12.2010 19:32:00 0 163c8142000000000072 27.11.2010 23:27:00 5 Cease Of Operation 14d70748000000000071 27.11.2010 23:27:00 5 Cease Of Operation 411726e0000000000054 04.08.2010 21:26:00 0 1cee2e2000000000002b 01.05.2010 15:32:00 0 2ee0af5a000000000021 24.04.2010 22:25:00 0 [↓] [vPodans] $crl.GetType().FullName System.Security.Cryptography.X509Certificates.X509CRL2 [↓] [vPodans]
Šīs raksts ir paredzēts latvijas IT administratoriem un izstrādātājiem. Ja runāt īsi, šīs ir lokālais MVP Summit, kur piedalās Baltijas MVP. Ja jums ir inetersanti uzzināt ko stāsta MVP, tad laipni lūgti. p.s. es arī piedalīšos šajā pasākumā un stastīšu par Powershell Remoting un tā iespējas. Un pasākuma programma:
10. februāris | Tallink Hotel Riga | Reģistrēties tagad
Laipni lūgti apmeklēt semināru Powered by MVP 10. februārī
viesnīcā Tallink Hotel Riga (Elizabetes iela 24).
Semināra laikā Microsoft eksperti un tehniksie speciālisti (Most Valuable Professionals) no Baltijas prezentēs Microsoft produktus, jaunākās tehnoloģijas un risinājumus IT Profesionāļiem un Izstrādātājiem. Prezentācijas noritēs Latviešu (LV), Krievu (RU) un Angļu (EN) valodās.
Šī ir brīnišķīga iespēja uzzināt veiksmes stāstus no Microsoft ekspertu pieredzes, kā arī jautri pavadīt laiku neformālās sarunās un laimēt balvas. Semināra neoficiālajā daļā tiks dota iespēja izbaudīt Xbox Kinect spēļu un balītes nepiespiesto atmosfēru ar dzērieniem, uzkodām un pārsteigumiem.
Lūdzam reģistrēties līdz 7. februārim: REĢISTRĀCIA
Seminārs ir BEZ MAKSAS, tādēļ nekavējoties reģistrēties, jo vietu skaits ir ierobežots!
Priecāsimies, ja pārsūtīsiet ielūgumu personām, kurām arī šis pasākums varētu būt saistošs.
DIENAS KĀRTĪBA:
Seminārs tiks atklāts ar galveno sesiju visiem dalībniekiem un tālāk tiks novirzīts divās paralēlās sesijās: IT Izstrādātājiem un IT Profesionāļiem.
Ar cieņu - Microsoft
Microsoft Latvija | www.microsoft.lv
Tallink hotel adrese un atrašanas vieta: http://hotels.tallink.com/en/mainMenu/tallinkHotelRiga/default.htm