サーバーにどのセキュリティ更新プログラムが適用されてないかを、MBSAとC#でチェックする

なかなかパッチを適用できないサーバーがあり、そのサーバーにどのパッチが当たっていないかを確認したいと思った時のメモ。

■環境


.NETのバージョンは「.NET Version Detector」を使用して確認した。
窓の杜 - インストール済みの.NET Frameworkのバージョンを調査する「.NET Version Detector」



■確認方法

MicrosoftMicrosoft Baseline Security Analyzer(MBSA)を公開しているので、それを利用する。
セキュリティ TechCenter - Microsoft Baseline Security Analyzer 2.2


インストールして実行する方法とコマンドラインは、以下を参照。ヘルプにも詳しい記載あり。
@IT - MBSAをオフラインで実行する


サーバー上に必要なファイルを置き、管理者のコマンドプロンプトで実行。

mbsacli.exe /xmlout /unicode /nd /nvc /wi /catalog wsusscn2.cab > mbsareport.xml

ちなみに、管理者のコマンドプロンプトでないと、エラーで動作しない。
参考:横着者のメモ帳 - いろいろ/VistaでMBSA2.1のmbsacliでセキュリティのCABファイルを読み込めません。



■作成したXMLファイルを見る

Microsoftより公開されている、XML Notepad 2007 を使ってみる。

■作成したファイルをCSVファイルへと変換する

XMLビューワでも見ることは可能だが、CSVに変換してみる*1


ソースコードを利用しなくても以下のようにしてExcelで見れるが、LINQ to XMLの勉強を兼ねてC#で組んでみる。
SEの雑記 - MBSA と DISM を使用した 2008 R2のパッチ適用



コンソールアプリケーションで作成。第一引数でxmlファイルのパスを引き渡すことも可能にしてみた。
ソースは以下、gist版はこちら

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Xml.Linq;

namespace MBSAToCSV
{
    class Program
    {
        static void Main(string[] args)
        {
            string xmlFilePath = "";

            if (args.Any())
            {
                xmlFilePath = args.First();
            }
            else
            {
                xmlFilePath = @"<デフォルトのXMLファイルパス>";
            }


            if (System.IO.File.Exists(xmlFilePath)) { }
            else
            {
                Console.WriteLine("ファイルがありません。");
                return;
            }

            

            var csv = System.Xml.Linq.XElement.Load(xmlFilePath).Elements("Check").Elements("Detail").Elements("UpdateData")
                             .Where(a => a.Attribute("IsInstalled").Value == "false")
                             .Select(b => string.Format("{0},{1},{2},{3}{4}",
                                                         (string)b.Attribute("ID"),
                                                         "KB" + (string)b.Attribute("KBID"),
                                                         (string)b.Element("Title"),
                                                         (string)b.Element("References").Element("InformationURL"),
                                                         Environment.NewLine
                                                         ))
                             .Aggregate(new StringBuilder(), (sb, s) => sb.Append(s), sb => sb.ToString());


            //  拡張子をxmlからstringに変換して保存
            string csvPath = xmlFilePath.Substring(0, xmlFilePath.Length - 3) + "csv";
            System.Text.Encoding enc = System.Text.Encoding.GetEncoding("shift_jis");
            using (System.IO.StreamWriter sw = new System.IO.StreamWriter(csvPath, false, enc))
            {
                // ヘッダーの先頭にID列を表記したい場合はダブルコーテーションで囲む
                // See: http://pasofaq.jp/office/excel/sylk.htm
                string header = "\"ID\",KB番号,タイトル,情報へのURL";
                sw.WriteLine(header);

                sw.WriteLine(csv);
            }

            Console.WriteLine("出力しました。");
        }
    }
}

■ソースを書く上での参考

1. ヘッダーの先頭に「ID」を埋めたかったため、ソース中ではダブルコーテーションで囲んだ。

パソコンFAQ - SYLK ファイルであることを確認しましたが、読み込むことができません

2. MSDNではクエリ式でのサンプルがあったが、あえてメソッド形式でソースを書いてみた。

MSDN - 方法 : XML からテキスト ファイルを生成する

*1:CSVフォーマットには準拠していないが...