PetSerAl在他上面的评论中提出了正确的想法:
一个解决方法是将当前位置更改为某个站点(cd IIS:\Sites\SomeSite
),无论到哪里都没有关系
这确实可以工作,但为什么不能从普通的文件系统提示符中工作呢?
为了发现New-WebBinding
为什么会表现出这种方式,我加载了包含此和其他WebAdministration
cmdlet的Microsoft.IIS.PowerShell.Provider
程序集到dotPeek中。该程序集位于GAC中,因此您可以告诉dotPeek“从GAC打开”。
加载后,我们感兴趣的类称为NewWebBindingCommand
。
经过粗略检查,我们可以看到所有参数属性都带有[Parameter(ValueFromPipelineByPropertyName = true)]
属性修饰符,所以这是一个好的开始,使用具有匹配属性名称的对象数组应该能够工作:
![enter image description here](https://istack.dev59.com/LSgTj.webp)
NewWebBindingCommand
最终继承自
System.Management.Automation.Cmdlet
,在这个实例中覆盖了
BeginProcessing
方法。如果被覆盖,PowerShell 会调用
BeginProcessing
并提供一次性的预处理功能来执行 cmdlet。
重要的是要理解,在将任何管道提供的命名参数处理并绑定到 cmdlet 的属性之前,会先调用 cmdlet 的
BeginProcessing
重写(请参阅:
Cmdlet Processing Lifecycle (MSDN))。
我们的
New-WebBinding
cmdlet 实现的
BeginProcessing
如下所示:
protected override void BeginProcessing()
{
base.BeginProcessing();
if (!string.IsNullOrEmpty(this.siteName))
return;
this.siteName = this.GetSiteName("Name");
}
this.siteName
是 Name
属性的私有成员值,该属性将绑定到 -Name
参数。当我们到达上面的 if(...)
语句时,`this.siteName` 尚未绑定(为 null),因此会进入以下代码块:
this.siteName = this.GetSiteName("Name")
调用
GetSiteName()
方法时,它会向上调用到命令的直接基类
HelperCommand
,该基类提供了许多对于许多不同的
WebAdministration
cmdlet都有用的“帮助器”方法。
HelperCommand.GetSiteName(string prompt)
方法如下所示:
protected string GetSiteName(string prompt)
{
PathInfo pathInfo = this.SessionState.PSVariable.Get("PWD").Value as PathInfo;
if (pathInfo != null && pathInfo.Provider.Name.Equals("WebAdministration", StringComparison.OrdinalIgnoreCase))
{
string[] strArray = pathInfo.Path.Split('\\');
if (strArray.Length == 3 && strArray[1].Equals("sites", StringComparison.OrdinalIgnoreCase))
return strArray[2];
}
if (!string.IsNullOrEmpty(prompt))
return this.PromptForParameter<string>(prompt);
return (string) null;
}
为了学习这个问题,我创建了自己的PowerShell cmdlet(称为Kevulator,抱歉),并引入了New-WebBinding cmdlet的BeginProcessing()代码以及New-WebBinding基类帮助方法GetSiteName()中的代码。
下面是在使用VS2015附加到一个PowerShell会话并将绑定管道传递到New-Kevulator时,在GetSiteName中断的屏幕截图:
![enter image description here](https://istack.dev59.com/HluGx.webp)
顶部的箭头说明我们的
Name
属性由
siteName
支持,尚未绑定,仍然为
null
(正如上面提到的会导致
GetSiteName
被执行)。我们刚刚跨越了这行上的断点。
PathInfo pathInfo =
this.SessionState.PSVariable.Get("PWD").Value as PathInfo
...它决定了我们所处的路径提供程序的类型。在这种情况下,我们在一个普通的文件系统 C:\>
提示符上,因此提供程序名称将是FileSystem
。我用第二个箭头突出了这一点。
如果我们Import-Module WebAdministration
并且CD IIS:
然后重新运行并再次中断,您会发现路径提供程序已更改为负责处理IIS:>
及其后面内容的WebAdministration
:
![enter image description here](https://istack.dev59.com/pERqc.webp)
如果
pathInfo
名称不等于
WebAdministration
,即我们不在一个
IIS:
提示符下,则代码会跳过并在命令行提示输入
Name
参数,就像您经历的那样。
如果
pathInfo
值是
WebAdministration
,则会发生以下两种情况之一:
如果路径为
IIS:
或
IIS:\Sites
,则代码会跳过并提示输入
Name
参数。
如果路径为
IIS:\Sites\SomeSiteName
,则返回
SomeSiteName
并有效地成为
-Name
参数值,然后从
GetSiteName()
函数回到
BeginProcessing
。
最后一个行为非常有用,因为如果您的当前路径是 IIS:\Sites\MySite
,那么您可以将一个绑定数组导入该站点,但不指定 Name
参数。或者,如果您在管道化对象的数组中提供了一个 Name
属性,则这些属性将覆盖从您的 IIS:\Sites\MySite
上下文中获取的默认站点名称。
所以,回到我们的代码,一旦 BeginProcessing
运行完毕,我们的管道命名参数现在实际上已经绑定,然后调用 ProcessRecord
方法,这是 New-WebBinding
必须执行的主要工作。
简而言之:
除非您将当前工作目录更改为 IIS 网站(例如 cd iis:\Sites\MySite
),否则 New-WebBinding
不会绑定管道参数。
PSObject
和PSCustomObject
的不同变化,但没有成功。好问题。 - KevMicrosoft.IIs.PowerShell.Provider
程序集,其中包含New-WebBinding
cmdlet,并且我们感兴趣的属性已经正确地标记为[Parameter(ValueFromPipelineByPropertyName = true)]
。 - Kevcd IIS:\Sites\SomeSite
),实际上无论更改为哪个站点都没有关系。 - user4003407