程式範例-IIS WMI 網站設定資料解析
| | | 0 | |
前一篇文章成功將 IIS 6 網站設定匯出成 JSON,不過原始資料太過龐雜,每筆虛擬目錄屬性超過140條,讓人眼花瞭亂。事實上因 IIS 設定具有繼承性,父目錄與子目錄的屬性絕大部分是相同的,針對某個虛擬目錄做的額外設定才是觀注焦點。例如:掛在可匿名存取 P 目錄下的 C 目錄被設成整合式驗證,描述 C 目錄設定時時只要列出 AuthNTLM = true 就好,與 P 目錄相同的設定可以全部省略。為實現這點,我想到一個簡單有效的演算法:拿子目錄的所有屬性跟父目錄比較,只顯示有差異部分。
WMI 匯出的 IISWebVirtualDirSetting 資料為 JSON 格式,轉為強型別處理起來才順手。講到這個不得不推 Visual Studio 強大的 Paste JSON As Classes 功能:選取 IISWebVirtualDirSetting 匯出的全部 JSON 內容,點選「Edit / Paste Special / Paste JSON As Classes」:

見證奇蹟的時刻… Visual Studio 自動依 JSON 資料產生對應型別,連 HttpCustomHeader 這種物件陣列屬性,陣列元素物件也被轉成強型別!

將 public class Class1 更名並轉為部分宣告 public partial class VirDirSetting,我另外再補上額外屬性及方法方便後續處理:
using Newtonsoft.Json; using System; using System.Collections.Generic; using System.Linq; using System.Reflection; using System.Text; using System.Threading.Tasks; namespace WmiDataAnalyzer { public partial class VirDirSetting
{ //所屬子網站 public List<VirDirSetting> Children = new List<VirDirSetting>();
//父網站名稱 public string ParentName;
//父網站物件 public VirDirSetting Parent; //所有可能的父網站名稱 public string[] AncestorNames
{ get
{ var p = this.Name.Split('/');
return Enumerable.Range(1, p.Length - 1) .Select(i => string.Join("/", p.Take(i).ToArray())).ToArray();
}
}
//層級深度 public int Level
{ get { return this.Name.Split('/').Length - 2; } }
//動態比對屬性用屬性集合 static Dictionary<string, PropertyInfo> Properties
{ get
{ return typeof(VirDirSetting)
.GetProperties(BindingFlags.Public | BindingFlags.Instance)
.Where(o => !"AncestorNames,Level,ScriptMaps".Split(',').Contains(o.Name))
.ToDictionary(o => o.Name, o => o);
}
}
//與Parent比較,找出有差異的設定 public Dictionary<string, string> GetExplicitSettings()
{ var diff = new Dictionary<string, string>();
if (this.Parent == null)
{ diff.Add("Remark", "**Root**");
}
else { foreach (var p in VirDirSetting.Properties.Values)
{ var pv = JsonConvert.SerializeObject(p.GetValue(this.Parent)); var cv = JsonConvert.SerializeObject(p.GetValue(this)); if (pv.CompareTo(cv) != 0) diff.Add(p.Name, cv);
}
}
return diff; }
}
}
寫一小段程式將 JSON 反序列化為物件集合,並找出彼此從屬關係,再印出網站結構及差異設定:
using Newtonsoft.Json; using System; using System.Collections.Generic; using System.IO; using System.Linq; using System.Text; using System.Threading.Tasks; namespace WmiDataAnalyzer { class Program { static void Main(string[] args)
{ Dictionary<string, VirDirSetting> data = JsonConvert.DeserializeObject<VirDirSetting[]>(
File.ReadAllText("Sample.json")).ToDictionary(o => o.Name, o => o); var roots = new List<VirDirSetting>(); //建立從屬關係 foreach (var vds in data.Values)
{ foreach (var anc in vds.AncestorNames)
{ if (data.ContainsKey(anc)) { vds.ParentName = anc;
vds.Parent = data[anc];
vds.Parent.Children.Add(vds);
break; }
}
if (string.IsNullOrEmpty(vds.ParentName))
{ roots.Add(vds);
}
}
//印出從屬關係 foreach (var root in roots)
{ DumpStructure(root);
}
Console.Read();
}
static void DumpStructure(VirDirSetting vds)
{ Console.WriteLine("{0}[{1}]", new string(' ', vds.Level * 4), vds.Name);
foreach (var kv in vds.GetExplicitSettings())
Console.WriteLine("{2} *{0}:{1}", kv.Key, kv.Value, new string(' ', vds.Level * 4 ));
foreach (var child in vds.Children)
{ DumpStructure(child);
}
}
}
}
我弄了一個測試網站結構如下,建立多個虛擬目錄並故意加入設定差異,例如:驗證方式、IP限制、不同ApplicationPool… 等等。

產生結果如下:

有少部分設定細節未包含在 IISWebVirtualDirSetting 中,要藉由其他 WMI 資料才能拼湊出完整設定。例如:虛擬目錄是否為網站應用程式可由 IISWebVirtualDir "AppRoot": null 與否判斷;IP 限制則要查詢 IISIpSecuritySetting,限定 IP 時會得到如下結果:
{ "Caption": null,
"Description": null,
"DomainDeny": [], "DomainGrant": [], "GrantByDefault": false,
"IPDeny": [], "IPGrant": [ "127.0.0.1, 255.255.255.255", "192.168.1.78, 255.255.255.255" ],
"Name": "W3SVC/1/ROOT/ParentWebApp/UNCVirtualDir",
"SettingID": null
},
由這些 WMI 資料,我們就能描繪現有網站的結構,進行檢視調整,並做為撰寫設定 IIS 網站自動腳本的依據。
Comments
Be the first to post a comment