1

I am trying to get this log4net customization to work with PowerShell PSObjects. Basically, this pattern layout will iterate over the object and dump its properties into CSV columns. Here is the code that does the reflection:

PropertyInfo[] properties = loggingEvent.MessageObject.GetType().GetProperties();
            foreach (PropertyInfo prop in properties)
            {
                object value = prop.GetValue(loggingEvent.MessageObject, null);
                loggingEvent.Properties[prop.Name] = value;
            }

This works fine when using a normal class in C#. It also works if I create a class using inline C# in PowerShell like this.

$code = @”

using System;
namespace CsvTest { 
    public class MyEvent
        {
            public string UserId { get; set; }
            public string Details { get; set; }
            public int EventCode { get; set; }

        }
    }
“@

Add-Type $code

$test = New-Object CsvTest.MyEvent
$test.UserId = "Andy"
$test.Details ="SomeStuff"
$test.EventCode = 10

$MyCommonLogger.Error($test)
$MyCommonLogger.Info($test)
$MyCommonLogger.Warn($test)

What doesn't work is if I create a custom PSObject. If I replace the $code with a PSCustom object such as

$obj = New-Object psobject -Property @{
                        "UserId" = "Andy";
                        "EventCode" = 100;
                        "Details" = "DetailInfoGoeshere"
                        }

Then it will just return Null. I have verified that this does in fact return null.

$obj = New-Object psobject -Property @{
                        "UserId" = "Andy";
                        "EventCode" = 100;
                        "Details" = "DetailInfoGoeshere"
                        }

$obj.GetType().GetProperties()

I suppose I could hack up CSVLogging Pattern layout and make a special case if the inbound object is a PSObject, but I'd rather not have to customize it for just one type of object. Is there a way in PowerShell to take a psobject and covert/cast it into something that I can use with GetType().GetProperties()?

4

2 回答 2

5

据我了解,根据以下结果:

Get-Member -InputObject $obj -Force

获取 psObject 属性的方法是:

$obj.psobject.properties
$obj.psobject.get_properties()

你不能编写动态创建类的 C# 代码吗?

于 2013-09-02T03:29:19.353 回答
0

我最终在 PowerShell 中编写代码来生成我需要的类。我添加了“Test-IsAssemblyLoaded”函数,这样它就不会尝试在同一个 PS 运行空间中两次加载同一个程序集。有点脏但有效。

Function Test-IsAssemblyLoaded {
param ($assembly)

$result = $false
try {
        $expression = "[$assembly]| out-null"
        invoke-expression $expression;
        $result = $true
    } 


catch {$result = $false}

return $result
}


Function Add-DotNetClass {
param(

[Parameter()]
$NameSpace = "PowerShell",

[Parameter()]
$Properties,

[Parameter()]
$ClassName

)

$code = @"

using System;

namespace $Namespace
{
    public class $className 
    {
        $(foreach ($p in $Properties)
                {
    "public $p {get;set;} `n"
                } )

    }
}
"@

if (Test-IsAssemblyLoaded "$Namespace.$ClassName") {Write-Warning "Assembly already loaded"}
else {Add-Type $code}

}

它似乎可以解决问题。

于 2013-09-05T17:06:24.827 回答