函数中的参数类型验证 - 二进制模块与脚本模块

时间:2018-01-23 13:45:58

标签: c# powershell type-conversion

在构建了许多PowerShell模块(包括二进制和脚本)之后,两个模型之间仍然存在一些不一致的问题,我无法理解这些模块。也许你们中的一个人可以对这个问题有所了解。

  1. 想象一个接受单个 nginx::nginx_servers: 'devops-alldomains': server_name: - '~^(?<fqdn>.+?)$' www_root: '/var/www/$fqdn' index_files: - 'index.php' try_files: - '$uri' - '$uri/' - '/index.php?$args' access_log: '/var/log/nginx/devops-alldomains-access.log' error_log: '/var/log/nginx/devops-alldomains-error.log' 'devops-alldomains-ssl': server_name: - '~^(?<fqdn>.+?)$' listen_port: '443' ssl_port: '443' www_root: '/var/www/$fqdn' ssl: true ssl_key: '/etc/ssl/www/$fqdn.key' ssl_cert: '/etc/ssl/www/$fqdn.crt' index_files: - 'index.php' try_files: - '$uri' - '$uri/' - '/index.php?$args' access_log: '/var/log/nginx/devops-alldomains-access-ssl.log' error_log: '/var/log/nginx/devops-alldomains-error-ssl.log' nginx::nginx_locations: 'devops-alldomains-loc': location: '~ \.php$' www_root: '/var/www/$fqdn' server: 'devops-alldomains' fastcgi: 'unix:/var/run/php7-fpm.sock' fastcgi_split_path: '^(.+\.php)(/.*)$' fastcgi_index: 'index.php' fastcgi_param: 'SCRIPT_FILENAME': '$document_root$fastcgi_script_name' 'devops-alldomains-ssl-loc': location: '~ \.php$' www_root: '/var/www/$fqdn' server: 'devops-alldomains-ssl' ssl: true ssl_only: true fastcgi: 'unix:/var/run/php7-fpm.sock' fastcgi_split_path: '^(.+\.php)(/.*)$' fastcgi_index: 'index.php' fastcgi_param: 'SCRIPT_FILENAME': '$document_root$fastcgi_script_name' 值的函数。在脚本函数中,我将其定义为DateTime参数;在C#函数中,参数的类型为[DateTime]。到目前为止,非常好。

  2. 现在想象一下将DateTime传递给函数,使用DateTime添加了一个额外的note属性。尽管被定义为Add-Member,但脚本函数参数很乐意接受此值,因为它实际上是[DateTime]包装原始PSObject(并且可能包含其他成员),在使用时将其解包 - 我希望我在这里使用正确的术语。正如预期的那样,传递(包裹的)DateTime之外的其他内容会失败,从而使函数或多或少具有类型安全性。

  3. 等效的C#函数将参数定义为DateTime,因此AFAIK无法访问其他参数。毕竟,参数提供的唯一“界面”来自DateTime类型。

  4. 或者,我可以将C#函数的参数类型定义为DateTime,但是我必须对PSObject的{​​{1}}进行自己的类型检查。

  5. 我的逻辑中有缺陷吗?或者,更重要的是,有没有办法绕过这个,所以我仍然可以将我的二进制模块的类型检查留给PowerShell?

    非常感谢提前!

1 个答案:

答案 0 :(得分:3)

你是对是错 - 它完全取决于目标参数是否是值类型(例如System.DateTime是结构) - 在这种情况下,在参数绑定期间,类型强制中的所有内容都会丢失。

但是,如果参数类型是引用类型,则可以使用PSObject.AsPSObject()“复活”PSObject包装器。

我在纯(-ish)PowerShell中提出了以下示例,以便于复制,但我相信它充分显示了我的观点

将以下内容粘贴到C#源文件中(例如,TestCmdlets.cs):

using System;
using System.Management.Automation;

namespace TestPSObject
{
  // This will be our parameter type
  public class TestObject {}

  // This will be our reference type test cmdlet
  [Cmdlet(VerbsDiagnostic.Test, "PSObjectByRef")]
  public class TestPSObjectByRefCommand : Cmdlet
  {
    [Parameter(Mandatory=true)]
    public TestObject TestObject
    {
      get { return testObject; }
      set { testObject = value; }
    }
    private TestObject testObject;

    protected override void ProcessRecord()
    {
      // If this works, we should receive an object with
      // identical psextended properties
      WriteObject(PSObject.AsPSObject(this.TestObject));
    }
  }

  // This will be our value type test cmdlet
  [Cmdlet(VerbsDiagnostic.Test, "PSObjectByValue")]
  public class TestPSObjectByValueCommand : Cmdlet
  {
    [Parameter(Mandatory=true)]
    public DateTime DateTime
    {
      get { return dateTime; }
      set { dateTime = value; }
    }
    private DateTime dateTime;

    protected override void ProcessRecord()
    {
      // If this works, we should receive an object with
      // identical psextended properties (hint: we won't)
      WriteObject(PSObject.AsPSObject(this.DateTime));
    }
  }
}

现在,在你的shell中,编译并导入我们的测试模块:

Add-Type -Path .\TestCmdlets.cs -OutputAssembly TestPSObject.dll -OutputType Library
Import-Module .\TestPSObject.dll

接下来,我们创建测试主题并为其添加注释属性:

$TestObject = New-Object TestPSObject.TestObject
$TestObject |Add-Member -MemberType NoteProperty -Name TestProperty -Value "Hi there!"
$DateTime = Get-Date
$DateTime |Add-Member -MemberType NoteProperty -Name TestProperty -Value "Hi there!"

当您取消引用Hi there!成员时,他们现在都返回字符串值TestProperty

现在进行实际测试:

$TestObjectAfter = Test-PSObjectByRef -TestObject $TestObject
$DateTimeAfter   = Test-PSObjectByValue -DateTime $DateTime

这仍将返回Hi there!

$TestObjectAfter.TestProperty

但这不会:

$DateTimeAfter.TestProperty