获取 IIS 7 站点属性

Posted

技术标签:

【中文标题】获取 IIS 7 站点属性【英文标题】:Getting IIS 7 Site properties 【发布时间】:2011-01-22 01:52:50 【问题描述】:

我有一个 C++ 应用程序需要检索 IIS 7 站点的属性(例如类似于 IIS6 中的元数据库属性 - PathAppFriendlyName 等)。

使用 IIS 7,我的代码是这样的:

    获取AppHostWritableAdminManager 并提交路径MACHINE/WEBROOT/APPHOST/Default Web Site/。 使用部分名称appSettings 调用GetAdminSection。 然后查看返回的集合并查找属性(例如Path)。

这适用于 IIS 6,但不适用于 IIS7/7.5。

我需要进行哪些更改才能完成这项工作?

【问题讨论】:

【参考方案1】:

在 IIS7 中,配置数据不存储在“元数据库”中,而且我们在 IIS6 中习惯的元数据库属性也不相同。 IIS7 将其大部分配置数据存储在以下文件中:

%systemroot%\System32\InetSrv\Config\applicationHost.config

还有其他文件,但为了回答这个问题,这是我们感兴趣的文件。

applicationHost.config 的文档可以在这里找到:

&lt;system.applicationHost&gt; - IIS.NETconfiguration Element [IIS 7 Settings Schema]</a><br><a href="/default/index/tourl?u=aHR0cDovL21zZG4ubWljcm9zb2Z0LmNvbS9lbi11cy9saWJyYXJ5L21zNjkwNTA3KHY9VlMuOTApLmFzcHg%3D" rel="nofollow" target="_blank">system.applicationHost Section Group [IIS 7 Settings Schema]

您可以在此处找到 IIS6 元数据库 -> IIS7 XML 配置映射列表:

Converting Metabase Properties to Configuration Settings [IIS 7]

例如,在 IIS6 中,站点的/root 的路径存储在IIsWebVirtualDirPath 属性中。即:

<IIsWebServer Location="/LM/W3SVC/67793744" AuthFlags="0" ServerAutoStart="TRUE" 
              ServerBindings="217.69.47.170:80:app2.dev" ServerComment="app2" /> 
<IIsWebVirtualDir Location="/LM/W3SVC/67793744/root" 
    AccessFlags="AccessRead | AccessScript" 
    AppFriendlyName="Default Application" 
    AppIsolated="2" 
    AppRoot="/LM/W3SVC/67793744/Root" 
    AuthFlags="AuthAnonymous | AuthNTLM" 
    DirBrowseFlags="DirBrowseShowDate | DirBrowseShowTime | DirBrowseShowSize |
            DirBrowseShowExtension | DirBrowseShowLongDate | EnableDefaultDoc" 
    Path="D:\websites\ssl-test\www\kerboom" 
    ScriptMaps="...">

但在 IIS7 中它的存储方式不同:

<sites>
    <site name="Default Web Site" id="1" serverAutoStart="true">
        <!-- this is the functional equivalent of the /root app in IIS6 -->
        <application path="/">
            <virtualDirectory path="/" 
                              physicalPath="%SystemDrive%\inetpub\wwwroot" />
        </application>
    </site>
<sites>

但是,如果您的代码必须同时使用 IIS6 和 IIS7,那么您可以安装 IIS6 管理兼容性组件。这将允许您使用传统的 IIS6 元数据库 API(例如 ADSI、System.DirectoryServices 等)访问 IIS7 站点属性。兼容层将为您将这些属性映射到新的 IIS7 架构。

本文的第一部分解释了如何在 Vista/Windows7/Windows 2008 上安装它:

How to install ASP.NET 1.1 with IIS7 on Vista and Windows 2008 - see step #1

更新:

不幸的是,C++ 不是我的强项。不过,我在 C# 中使用 COM Interop 编写了一个示例来演示如何使用 AppHostWritableAdminManager

IAppHostWritableAdminManager wam = new AppHostWritableAdminManager();
IAppHostElement sites = 
   wam.GetAdminSection("system.applicationHost/sites", "MACHINE/WEBROOT/APPHOST");
IAppHostElementCollection sitesCollection = sites.Collection;

long index = FindSiteIndex(sitesCollection, "MySite");
if(index == -1) throw new Exception("Site not found");

IAppHostElement site = sitesCollection[index];
IAppHostElementCollection bindings = site.ChildElements["bindings"].Collection;

for (int i = 0; i < bindings.Count; i++)

  IAppHostElement binding = bindings[i];
  IAppHostProperty protocolProp = binding.GetPropertyByName("protocol");
  IAppHostProperty bindingInformationProp = 
      binding.GetPropertyByName("bindingInformation");

  string protocol = protocolProp.Value;
  string bindingInformation = bindingInformationProp.Value;

  Debug.WriteLine("0 - 1", protocol, bindingInformation);



static long FindSiteIndex(IAppHostElementCollection sites, string siteName)

  for (int i = 0; i < sites.Count; i++)
  
    IAppHostElement site = sites[i];
    Debug.WriteLine(site.Name);
    IAppHostProperty prop = site.GetPropertyByName("name");
    if(prop.Value == siteName)
    
      return i;
    
  
  return -1;

上面的代码在&lt;sites&gt; 集合中找到了一个名为“MySite”的站点。然后它检索站点的&lt;bindings&gt; 集合并打印每个绑定protocolbindingInformation 属性。

您应该能够相当轻松地将其转换为 C++。

回答您评论中的问题 -

例如,路径 system.applicationHost/Sites 将获得 我的网站列表。有没有 访问我的服务器的绝对方法 像这样的绑定(例如通过 正在做 system.applicationHost/站点/默认 网站/绑定

使用AppHostWritableAdminManager 时,没有快捷方式可以直接访问您要检查/修改的站点或其属性。在上面的示例中,您会看到我需要遍历站点集合以找到我感兴趣的站点。原因是AppHostWritableAdminManager 将所有内容视为元素和元素的集合。这是一个相当基本的 API。即使使用托管的Microsoft.Web.Administration API,您也会发现虽然有一些不错的属性,例如Site.Bindings,但这些只是AppHostWritableAdminManager 的伪装包装。

事实上,如果我想找到一个站点,我仍然需要在 for 循环中搜索 Sites 集合,或者如果我使用的是 C#3.5 或更高版本,则需要添加一些 LINQ 糖:

using(ServerManager serverManager = new ServerManager())

    Site x = serverManager.Sites.FirstOrDefault(s => s.Name == "MySite");

Site 的基类是ConfigurationElement,它在引擎盖下封装了对IAppHostElement 的访问。

一旦您了解了一些基本的快捷方式包装器属性,我们在托管代码中配置 IIS(例如 IIS FTP)的大部分工作就是元素、属性和元素集合。

更新 2:

请记住,我一生中从未写过一行 C++。没有清除字符串或对象:

#include "stdafx.h"
#include <windows.h>
#include <stdio.h>
#include <ahadmin.h>
#include <crtdbg.h>

static IAppHostElement* 
   FindSite(IAppHostElementCollection *pCollection, BSTR bstrSiteName);

int _tmain(int argc, _TCHAR* argv[])

  CoInitialize(NULL);

  IAppHostWritableAdminManager *pMgr = NULL;
  IAppHostElement *pElem = NULL;
  IAppHostElementCollection *pSitesCollection = NULL;
  IAppHostElement *pSite = NULL;
  IAppHostElement *pBindings = NULL;
  IAppHostElement *pBinding = NULL;
  IAppHostElementCollection *pBindingsCollection = NULL;
  IAppHostChildElementCollection *pChildElements = NULL;
  IAppHostProperty *pProtocol = NULL;
  IAppHostProperty *pBindingInformation = NULL;

  BSTR bstrSectionName = SysAllocString( L"system.applicationHost/sites" );
  BSTR bstrConfigCommitPath = SysAllocString( L"MACHINE/WEBROOT/APPHOST" );
  BSTR bstrSiteName = SysAllocString( L"MySite" );
  BSTR bstrBindingsConst = SysAllocString( L"bindings" );
  BSTR bstrBindingProtocol = SysAllocString( L"protocol" );
  BSTR bstrBindingInformation = SysAllocString( L"bindingInformation" );

  VARIANT vtPropertyName;
  VARIANT vtIndex;

  HRESULT hr = S_OK;

  hr = CoCreateInstance( __uuidof(AppHostWritableAdminManager), NULL, 
      CLSCTX_INPROC_SERVER, __uuidof(IAppHostWritableAdminManager), (void**) &pMgr);

  hr = pMgr->GetAdminSection(bstrSectionName, bstrConfigCommitPath, &pElem);
  hr = pElem->get_Collection(&pSitesCollection);

  pSite = FindSite(pSitesCollection, bstrSiteName);

  hr = pSite->get_ChildElements(&pChildElements);

  vtPropertyName.vt = VT_BSTR;
  vtPropertyName.bstrVal = bstrBindingsConst;

  hr = pChildElements->get_Item(vtPropertyName, &pBindings);
  hr = pBindings->get_Collection(&pBindingsCollection);

  DWORD bindingsCount;
  hr = pBindingsCollection->get_Count(&bindingsCount);

  for(int i = 0; i < bindingsCount; i++)
  
    vtIndex.lVal = i;
    vtIndex.vt = VT_I4;
    hr = pBindingsCollection->get_Item(vtIndex, &pBinding);

    hr = pBinding->GetPropertyByName(bstrBindingProtocol, &pProtocol);
    hr = pBinding->GetPropertyByName(bstrBindingInformation, &pBindingInformation);

    BSTR bstrProtocol;
    BSTR bstrBindingInformation;

    hr = pProtocol->get_StringValue(&bstrProtocol);
    hr = pBindingInformation->get_StringValue(&bstrBindingInformation);

    _tprintf(_T("Protocol: %s, BindingInfo: %s\n"), bstrProtocol, bstrBindingInformation);
  

  CoUninitialize();
  return 0;


IAppHostElement* FindSite(IAppHostElementCollection *pCollection, BSTR bstrSiteName)

  DWORD count = -1;
  pCollection->get_Count(&count);

  BSTR bstrPropName = SysAllocString( L"name");

  for(DWORD i = 0; i < count; i++)
  
    IAppHostElement *site = NULL;
    IAppHostProperty *prop = NULL;
    BSTR bstrPropValue;

    HRESULT hr = S_OK;

    VARIANT vtCount;
    VariantInit(&vtCount);
    vtCount.lVal = i;
    vtCount.vt = VT_I4;

    hr = pCollection->get_Item(vtCount, &site);
    hr = site->GetPropertyByName(bstrPropName, &prop);
    hr = prop->get_StringValue(&bstrPropValue);

    if(wcscmp(bstrPropValue, bstrSiteName) == 0)
    
      return site;
    
  

  return NULL;

【讨论】:

凯夫,非常感谢您的回复。您能否请我参考“管理部分”和提交路径的解释?例如,路径 system.applicationHost/Sites 将使我进入站点列表。有没有绝对的方法可以像这样访问我的服务器绑定(例如通过执行 system.applicationHost/Sites/Default Web Site/Bindings? @ron - 请查看我的更新答案。希望这能解决问题。 再次感谢 - 我想我开始明白这一点了。基本上,要访问我的服务器绑定,我需要在 system.applicationHost/Sites 部分中找到我的网站,然后迭代集合并找到我的网站。然后,我需要迭代我的站点的子元素并查找绑定。这很好用,但是有没有办法直接访问绑定(可能类似于 system.applicationHost/Default Web Site/Bindings?请告诉我您的想法 - 再次感谢 @ron - 你不能直接去一个站点并获得它的绑定。你必须深入挖掘才能找到你想要的东西。我在 C++ 中添加了一个我拼凑在一起的示例。另请注意,我一生中从未编写过一行 C++,因此请注意,这是一个完全肮脏的 hack :)。

以上是关于获取 IIS 7 站点属性的主要内容,如果未能解决你的问题,请参考以下文章

如何使用 ASP.NET Core RC2 MVC6 和 IIS7 获取当前 Windows 用户

在多个绑定上托管 IIS 站点时如何获取正确的本地地址 URI?

C#获取IIS所有站点及虚拟目录和应用程序(包含名称及详细信息)

用powershell脚本实现zabbix LLD 监控IIS站点

如何取消服务器/主机空间目录脚本的执行权限

IIS MIME 类型的元数据库路径