Posts on this page:

Welcome to my new web home!


Finally I did it! I burned my old SharePoint blog and R.I.P.’ed my former Russian blog (DasBlog) as promised.

The problem

Just to recall the history. Several years ago I realized that I need a new website/portal to host my stuff. Initially I looked for a ready solution that would match my humble requirements:

  1. It should support hierarchical site directories to organize content;
  2. It should support SQL database;
  3. It should support multi-level hierarchical content categories;
  4. It should support an ability to control rendering;
  5. It should support old URLs and redirect to migrated content. It was very important, because I realize that there are tons reference links to my previous weblogs and can’t simply break them;
  6. Should use friendly URLs;
  7. Preferably, it should be .NET-based.

There were several candidates:

  • SharePoint (what? Again?)
  • Orchard
  • BlogEngine.NET
  • DasBlog (again)

After testing each from the list, neither matched all my requirements. I used to like Scott Hanselman’s DasBlog, as it matched almost all requirements, except first two. After that I decided to write my own blog/website engine with black-jack and hookers.


The first problem was that I don’t have web-application development experience. Many thanks to Sergey Zwezdin, who helped me to make first steps and provided valuable support during development. He suggested to try ASP.NET MVC + Entity Framework (EF) as a start point. Relatively quickly I learned basic concepts and some non-trivial things. Site development started about 2 years ago, but last year I realized that this is a bullshit, not a website and started again with new knowledge. Due to my studies at university, the progress was quite slow and only after exams I was able to work on website intensively.

The biggest conceptual problem was with hierarchical site directories, where each directory would have their own settings and filters. Once I implemented this, I faced another issue: ASP.NET routing failed to differentiate directories and pages with matching names. Actually, this was the only thing I couldn’t handle correctly and was forced to apply extensions to pages (like in classic WebForms). But I don’t care too much about this, not a big deal.

Second phase was existing content migration. Neither, DasBlog, nor SharePoint allows to export content in BlogML format. Since DasBlog uses XML to store site content, I quickly converted them to BlogML, including comments. With SharePoint this trick didn’t worked, so I used my small Metaweblog API client to grab posts from database.

Next phase was HTML content rendering control. I wanted to template some parts of page contents. For example, provide an unified PowerShell syntax highlighting, PowerShell console box rendering and so on. A great HtmlAgilityPack library became extremely handy to clear inline styles, transform HTML fetch images, rewrite embedded links to a new format and much more. In a fully automated way! I can guarantee that any direct link to any of my previously published page will work by redirecting to a new URL. Now this library is used to replace HTML at runtime. I wrote nice PowerShell syntax highlighter (by using built-in PowerShell tokenizer) and reused XML/HTML syntax highlighting from PS Cmdlet Help Editor and much more. JavaScript-free.

Once this major task was done, I started to work on related stuff, like Metaweblog API server (to post articles via Windows Live Writer), management system and UX. Eventually, I ended up with 5 MVC controllers and 5k+ (according to Visual Studio metrics) lines of code.

At this point, my new web site implements almost all my wishes, except the biggest one: site search. Unfortunately, there are no easy-to-use search engines for .NET applications, but I’m going to work on it. There are two search engines: Lucene.NET and Solr.NET, but they doesn’t look easy and requires some research.

What next?

There are still places to improve. My general roadmap includes:

  • Research an ability to add on-site search;
  • Replace heavy CKEditor with lightweight editor in the comment boxes;
  • Re-categorize existing content in main weblog;
  • Implement cuts for main page feed;
  • Move external content to this web site.

Final word

As a final word, I encourage you, my readers, to update bookmarks, links (if possible) to my website and RSS feed. For any questions, and/or issues, please, report them in the contact form.

And do not forget to visit my website for new content. Thank you, very much!

Certificate Rules may not work in Software Restriction Policies


Consider the following scenario. You configured Software Restriction Policies (SRP) to allow run all applications that are signed by the specific signer by creating a Certificate Rule against the signer certificate.

When the policy is refreshed on the client, user cannot run the application, because it is blocked by Software Restriction Policies.



This behavior occurs when the certificate is issued by a Certification Authority (CA) which do not include or provide incorrect issuer information in the Authority Information Access (AIA) extension in the signing certificate. In addition, intermediate CA certificate is not installed in the local store. SRP reads only signing certificate in the digital signature and ignores the rest certificates.

This issue may occur when the signing certificate was issued by Thawte due to their CA certificate distribution policy.


This behavior is by design. No bug fixes are available. See Workaround section for example steps to overcome the issue.


Perform the following steps to install intermediate CA certificate to local certificate store.

Option 1 is a general guidance for intermediate CA certificate retrieval. Option 2 is used only for signing certificates issued by Thawte.

Option 1

Option 2

The following steps can be used to save Thawte Code Signing CA – G2 certificate to a file:

  1. Run Notepad;
  2. Copy the following text and paste it to Notepad:

    -----END CERTIFICATE-----

  3. Click File menu and click Save or Save As...;
  4. In the Save dialog, select the path and file name. Append “.cer” extension to the end of the file name;
  5. In the Save as type drop-down list, select All Files (*.*);
  6. Make sure that Encoding drop-down list is set to ANSI:
  7. Click Save button to save the file.

CA certificate installation instructions:

There are three options to install CA certificate to local certificate store:

  • Option 1 installs CA certificate to local machine only;
  • Option 2 installs CA certificate to a set of computers depending on Group Policy object scope in Active Directory;
  • Option 3 installs CA certificate to all machines in the current Active Directory forest

Option 1

  1. Log on to target computer with local Administrator permissions;
  2. Run Command Prompt in elevated mode;
  3. In the Command Prompt, type the following command:

    certutil -f –addstore CA path\cacertfile.cer

    change “path\cacert.cer” part with actual path and file name.
  4. Close Command Prompt.

Option 2

  1. Log on to a computer where Group Policy management tools are installed with Domain Admins permissions;
  2. Run Group Policy Management console (gpmc.msc);
  3. Edit existing or create a new Group Policy Object (GPO).
  4. In the GPO editor, expand Computer Configuration\Policies\Windows Settings\Security Settings\Public Key Infrastructure.
  5. Under Public Key Infrastructure node right-click on Intermediate Certification Authorities and click Import;
  6. Follow Certificate Import Wizard instructions to import CA certificate;
  7. Close GPO editor and Group Policy Management console.

When completed, refresh the group policy on the target clients by running “gpupdate /force” command.

Option 3

  1. Log on to any Active Directory member with Enterprise Administrator permissions;
  2. Run Command Prompt in elevated mode;
  3. In the Command Prompt, type the following command:

    certutil –dspublish –f path\cacertfile.cer SubCA

    change “path\cacert.cer” part with actual path and file name.
  4. Close command Prompt.

When completed, refresh the group policy on the target clients by running “gpupdate /force” command.

    Note: Option 3 requires that Autoenrollment policy is enabled on clients.

    • Windows XP Professional
    • Windows Server 2003 (all editions)
    • Windows Vista Business, Ultimate, Enterprise
    • Windows Server 2008 (all editions)
    • Windows 7 Professional, Ultimate, Enterprise
    • Windows Server 2008 R2 (all editions)
    • Windows 8 Professional, Enterprise
    • Windows Server 2012 (all editions)
    • Windows 8.1 Professional, Enterprise
    • Windows Server 2012 R2 (all editions)

    Test PFX (PKCS#12) file and PFX password with CryptoAPI in PowerShell

    Today I want to present another useful CryptoAPI functions to use when working with PFX (PKCS#12) certificates.

    1. Determine if the BLOB is PFX without having to pass a password;
    2. Test PFX password.

    Of course, you can try to use appropriate X509Certificate2 class constructor, but this approach is faster and do not require key import in cryptographic provider and other actions performed by X509Certificate2 constructor. This functionality is implemented in two CryptoAPI functions:

    1. PFXIsPFXBlob
    2. PFXVerifyPassword

    And here is complete solution:

    $signature = @"
    [DllImport("Crypt32.dll", CharSet = CharSet.Auto, SetLastError = true)]
    public static extern bool PFXIsPFXBlob(
    [DllImport("Crypt32.dll", CharSet = CharSet.Auto, SetLastError = true)]
    public static extern bool PFXVerifyPassword(
        string szPassword,
        int dwFlags
    [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Auto)]
    public struct CRYPTOAPI_BLOB {
        public int cbData;
        public IntPtr pbData;
    Add-Type -MemberDefinition $signature -Namespace PKI -Name Crypt32
    function Test-CertIsPfx ([Byte[]]$RawData) {
        # create buffer in an unmanaged memory to store raw data
        $pbData = [Runtime.InteropServices.Marshal]::AllocHGlobal($RawData.Length)
        # copy bytes to unmanaged buffer:
        # create CRYPTOAPI_BLOB structure
        $blob = New-Object PKI.Crypt32+CRYPTOAPI_BLOB -Property @{
            cbData = $RawData.Length
            pbData = $pbData
        # call the PFXVerifyPassword to test the content. The function returns $true
        # if byte array represents PFX file.
        # release unmanaged buffer:
    function Test-PfxPassword ([Byte[]]$RawData, [string]$Password) {
        # create buffer in an unmanaged memory to store raw data
        $pbData = [Runtime.InteropServices.Marshal]::AllocHGlobal($RawData.Length)
        # copy bytes to unmanaged buffer:
        # create CRYPTOAPI_BLOB structure
        $blob = New-Object PKI.Crypt32+CRYPTOAPI_BLOB -Property @{
            cbData = $RawData.Length
            pbData = $pbData
        # call the PFXVerifyPassword to test the password. The function returns $true
        # if password is correct
        [PKI.Crypt32]::PFXVerifyPassword($blob, $Password, 0)
        # release unmanaged buffer:

    and usage:

    [↓] [vPodans] $bytes = [io.file]::ReadAllBytes(".\3.pfx")
    [↓] [vPodans] $bytes2 = [io.file]::ReadAllBytes(".\pem.txt")
    [↓] [vPodans] Test-CertIsPfx $bytes
    [↓] [vPodans] Test-CertIsPfx $bytes2
    [↓] [vPodans] Test-PfxPassword $bytes "1"
    [↓] [vPodans] Test-PfxPassword $bytes "other password"
    [↓] [vPodans]

    Note: PFX files must be stored in a pure binary format. Unlike regular certificates, PFX do not support base64 encoding in files.

    In these examples, I read two files, one PFX, another – “whateverelse” and passed them to Test-CertIsPfx function. As you see, only bytes from “3.pfx” file returned $true. And attempted to guess the password and guessed from the first attempt!!! (joke). This is something you can write during morning coffee/tea :)

    Convert data between binary, hex and Base64 in PowerShell

    Point Of Interest

    Yesterday I asked in Twitter, who can convert byte array to a formatted hex string in PowerShell in 5 minutes. I got one solution with the reference to Format-Hex function. Then I asked opposite question: can you convert formatted hex dump with address and ASCII panes back to byte array in PowerShell in 5 minutes? Didn’t get any response.

    This subject is interesting and sometimes is necessary. Due to my specialization (cryptography), I have to deal with these formats often. And not only hex, Base64 with and without headers as well.

    Common formatting examples

    To make the subject clear, I provide some formatted examples:

    • Unformatted raw hex string:
    • Formatted hex string, 16 octets per row:
    30 81 bd 30 81 98 30 09  06 05 2b 0e 03 02 1a 05
    00 30 47 31 13 30 11 06  0a 09 92 26 89 93 f2 2c
    64 01 19 16 03 63 6f 6d  31 17 30 15 06 0a 09 92
    • Hex string with address and ASCII values:
    0000	30 81 bd 30 81 98 30 09  06 05 2b 0e 03 02 1a 05   0..0..0...+.....
    0010	00 30 47 31 13 30 11 06  0a 09 92 26 89 93 f2 2c   .0G1.0.....&...,
    0020	64 01 19 16 03 63 6f 6d  31 17 30 15 06 0a 09 92   d....com1.0.....
    • Raw Base64
    • Base64 with header:
    -----BEGIN XYZ-----
    -----END XYZ-----

    Converting the byte array to one of these formats may be quite challenging. But real challenge is to convert formatted data back to binary copy.

    CryptoAPI or cheat sheet

    To work this out, you have to check and, most likely, significantly upgrade your string parsing skills in PowerShell. But it is worth to mention Windows built-in solutions which can be utilized in PowerShell.

    Two things to know:

    1. Bad thing: we will deal with Win32 native functions
    2. Good thing: it will take just few lines of code :)

    We will need two functions:

    At first, let’s write unmanaged function signatures:

    $signature = @"
    [DllImport("Crypt32.dll", CharSet = CharSet.Auto, SetLastError = true)]
    public static extern bool CryptStringToBinary(
        string pszString,
        int cchString,
        int dwFlags,
        byte[] pbBinary,
        ref int pcbBinary,
        int pdwSkip,
        ref int pdwFlags
    [DllImport("Crypt32.dll", CharSet = CharSet.Auto, SetLastError = true)]
    public static extern bool CryptBinaryToString(
        byte[] pbBinary,
        int cbBinary,
        int dwFlags,
        StringBuilder pszString,
        ref int pcchString
    Add-Type -MemberDefinition $signature -Namespace PKI -Name Crypt32 -UsingNamespace "System.Text"
    $encoding = @{'Base64Header' = 0; 'Base64' = 1; 'HexRaw' = 12; 'Hex' = 4; 'HexAddr' = 10;
        'HexAscii' = 5; 'HexAddrAscii' = 11}

    Tip: I used a simplified encoding set for brevity.

    The signatures are fairly simple. Key notes about these functions:

    • Functions returns Boolean which tells whether the input string is in the same format being requested in the dwFlags parameter.
    • These functions require two calls, where first call returns the size for return value.
    • Return value size and actual value is returned in the pcbBinary and pbBinary parameters, respectively, in the CryptStringToBinary function.
    • Return value size and actual value is returned in the pszString and pcchString parameters, respectively, in the CryptBinaryToString function.
    • flags CRYPT_STRING_ANY, CRYPT_STRING_HEX_ANY and CRYPT_STRING_BASE64_ANY are not supported in CryptBinaryToString functions.

    Binary to string. Examples

    Now we will look into some examples. The full sample code with comments:

    # say, it is our byte array
    [Byte[]]$array = 0..49
    # initialize variable to receive resulting string length
    $pcchString = 0
    # call the CryptBinaryToString function to get string length. pszString is $null for the first call
    if ([PKI.Crypt32]::CryptBinaryToString($array,$array.Length,$encoding['Base64'],$null,[ref]$pcchString)) {
        # instantiate a StringBuilder object with required size
        $SB = New-Object Text.StringBuilder $pcchString
        # call the function again and pass StringBuilder into pszString parameter
        # display produced output
    } else {
        Write-Warning $((New-Object ComponentModel.Win32Exception ([Runtime.InteropServices.Marshal]::GetLastWin32Error())).Message)

    When using the code for different formats, only dwFlags parameter is changed in both function calls. And here is the output for different formats:

    • To Base64
    • To raw hex string
    • To hex with 16 octets per row
    00 01 02 03 04 05 06 07  08 09 0a 0b 0c 0d 0e 0f
    10 11 12 13 14 15 16 17  18 19 1a 1b 1c 1d 1e 1f
    20 21 22 23 24 25 26 27  28 29 2a 2b 2c 2d 2e 2f
    30 31
    • To hex with address pane
    0000    00 01 02 03 04 05 06 07  08 09 0a 0b 0c 0d 0e 0f
    0010    10 11 12 13 14 15 16 17  18 19 1a 1b 1c 1d 1e 1f
    0020    20 21 22 23 24 25 26 27  28 29 2a 2b 2c 2d 2e 2f
    0030    30 31
    • To hex with ASCII pane
    00 01 02 03 04 05 06 07  08 09 0a 0b 0c 0d 0e 0f   ................
    10 11 12 13 14 15 16 17  18 19 1a 1b 1c 1d 1e 1f   ................
    20 21 22 23 24 25 26 27  28 29 2a 2b 2c 2d 2e 2f    !"#$%&'()*+,-./
    30 31                                              01
    • To hex with both, address and ASCII panes
    0000    00 01 02 03 04 05 06 07  08 09 0a 0b 0c 0d 0e 0f   ................
    0010    10 11 12 13 14 15 16 17  18 19 1a 1b 1c 1d 1e 1f   ................
    0020    20 21 22 23 24 25 26 27  28 29 2a 2b 2c 2d 2e 2f    !"#$%&'()*+,-./
    0030    30 31                                              01

    fast, quick, elegant!

    String to binary. Examples

    You can say that binary to hex is very simple, but opposite conversion is more sophisticated. You may need to determine whether the hex dump contains address and/or ASCII panes and ignore them during conversion. Hopefully, CryptStringToBinary function will take care of them. Here is another function to convert formatted string to a byte array:

    function Convert-HexToBinary ([string]$hex) {
        # decoding hashtable contains universal flags: Base64Any and HexAny. The function attempts to
        # get the correct input string format and then decode it
        $decoding = @{'Base64Header' = 0; 'Base64' = 1; 'HexRaw' = 12; 'Hex' = 4; 'HexAddr' = 10;
            'HexAscii' = 5; 'HexAddrAscii' = 11; 'Base64Any' = 6; 'HexAny' = 8}
        # initialize variables to receive resulting byte array size and actual input string format
        $pcbBinary = 0
        $pdwFlags = 0
        # call CryptStringToBinary to get resulting byte array size and actual input string format
        if ([PKI.Crypt32]::CryptStringToBinary($hex,$hex.Length,$decoding['HexAny'],$null,[ref]$pcbBinary,0,[ref]$pdwFlags)) {
            # create enough large byte array
            $array = New-Object byte[] -ArgumentList $pcbBinary
            # call the function again to write converted bytes to a byte array
        } else {
            Write-Warning $((New-Object ComponentModel.Win32Exception ([Runtime.InteropServices.Marshal]::GetLastWin32Error())).Message)

    Look at this:

    [↓] [vPodans] $string = @"
    >> 0000    00 01 02 03 04 05 06 07  08 09 0a 0b 0c 0d 0e 0f
    >> 0010    10 11 12 13 14 15 16 17  18 19 1a 1b 1c 1d 1e 1f
    >> 0020    20 21 22 23 24 25 26 27  28 29 2a 2b 2c 2d 2e 2f
    >> 0030    30 31
    >> "@
    [↓] [vPodans] $array = Convert-HexToBinary $string
    Input string encoding: 10
    [↓] [vPodans] $array[0..10]
    [↓] [vPodans] $array.Length
    [↓] [vPodans]

    As you can see, we got our original byte array! Exactly 50 bytes! I showed the $pdwFlags variable which stores actual format type of input string. 10 stands for CRYPT_STRING_HEXADDR. Don’t believe? Check CryptStringToBinary function description page.

    You think it is all? Hell no! If we put comments, will it work?

    [↓] [vPodans] $string = @"
    >> 0000    00 01 02 03 04 05 06 07  08 09 0a 0b 0c 0d 0e 0f ;line one
    >> 0010    10 11 12 13 14 15 16 17  18 19 1a 1b 1c 1d 1e 1f ; line two
    >> 0020    20 21 22 23 24 25 26 27  28 29 2a 2b 2c 2d 2e 2f ; FF BB
    >> 0030    30 31
    >> "@
    [↓] [vPodans]  $array = Convert-HexToBinary $string
    Input string encoding: 11
    [↓] [vPodans] $array[0..10]
    [↓] [vPodans] $array.Length
    [↓] [vPodans]

    The function is enough smart. Exactly 50 bytes. Though, the function identified the string as hex string with address and ASCII panes. But the result is achieved!

    Final word

    Today we explored another powerful and useful feature from Win32 repository. Decent google/bing skills and an ability to write native function signature definitions in PowerShell allows you to solve this task in 5 minutes! Not all love Win32, but sometimes it simply saves many hours of your work. Spend it wisely!


    PowerShell PKI module, v3.1

    Yesterday I released another version of PowerShell PKI module v3.1.

    Though, this release is not that big like v3.0. Only 1 (one!) new command is added (Get-EnterprisePKIHealthStatus) and various bug fixes (as usually). On the other hand it includes very important things which are hidden behind the scene.

    The project is growing and I have to battle hard with poor design decisions I made previously. Of course, I could break everything and make it as per all guidelines. However, it is too late, 3000 downloads for the past 7 months is not a joke and I can’t simply break it.

    Next sections will cover some development details, so you can scroll down to the end of post to get the right link :)

    ASN.1 type system

    First, I almost polished my ASN.1 parser, it is now rewritten by using more efficient code. For one function I was forced to look for some help on StackOverflow. The lesson is learned and now I have fairly efficient code where it matters most. You can ask, why I pay so much attention to that ASN.1, while even PKI administrators (not to tell about other systems administrators and PowerShell users) have a very-very little knowledge about ASN and do not use it directly. The truth is that entire Internet PKI communication system is based on ASN.1. What is your digital certificate? It is ASN.1. What is your certificate request? It is ASN.1. What is PKCS#X? It is ASN.1. An ability to read, decode, encode ASN.1 data is a “must have” for any PKI developer. CryptoAPI has a rich support of ASN.1, but .NET do not. Although I like CryptoAPI as it can do things in few lines and very quickly while managed implementation is bigger and slower, I decided to move common classes to managed code. Mostly because of unmanaged memory management. When you create CRL object, its handle is not released in normal ways and users do not release them as well.

    I’m planning to extend my own ASN.1 type system support by adding classes for each universal tag. Currently, only two classes are exposed:, but there are a bit more (currently marked private):


    In addition, entire ASN namespace will be removed from PKI.Core.dll library to its own assembly, because I’m actively using it in other projects.

    X509Certificates namespace

    I’m constantly adding new certificate/CRL extension support (both, Microsoft-specific and Internet PKI) in the X509Certificates namespace to provide ease access to extension data. Worth to mentioned that I rewrote X509CRLDistributionPointsExtension class to fully match RFC5280 specifications. Now this class can decode partitioned and non-standard (though, within RFC standard) CDP extension. Although, this extension now looks a bit complicated, a shortcut method GetURLs helps you to easily access URLs in the extension.

    Check this namespace with each release, maybe you can find there something useful for you.

    Another feature (planned) is to add an ability to read certificate properties when they are installed in the store. Sometimes they may have interesting details. For example, information about private key, enrollment options and so on:


    Note that not all details are shown in the certificate UI window. I’m thinking about the best way to implement it, but would be a great feature


    With this release, I officially published an official project development roadmap. It reflects my personal vision of module extension with added community requests I consider important or interesting.


    >> PowerShell PKI v3.1 <<