Powershell重新评估字符串到数组

Pet*_*ete 4 arrays powershell expression

我有很多这样的字符串,我希望 powershell 重新评估\转换为数组(就像如果您在 ISE 中编写不带单引号的相同代码会发生什么)。

$String = '@("a value","b value","c value")'

有没有比从字符串中删除“@”和“()”并使用 -split 更简单的方法?

我在这里先向您的帮助表示感谢。

San*_*zon 7

只要字符串包含有效的表达式,就可以使用以下[scriptblock]::Create(..)方法:

$String = '@("a value","b value","c value")'
& ([scriptblock]::Create($String))
Run Code Online (Sandbox Code Playgroud)

Invoke-Expression也会起作用,在这种情况下基本上是相同的事情。


然而,正如zett42 在评论中指出的那样,脚本块的一个很好的功能是,使用它们我们可以验证其CheckRestrictedLanguage方法是否禁止任意代码执行。

在下面的示例中,Write-Host是一个允许的命令,并且包含 only 的字符串'Write-Host "Hello world!"'不会引发异常,但是,赋值语句或未列出的任何其他命令$allowedCommands将引发异常,并且脚本块将不会被执行

$String = @'
Write-Host "Hello world!"
$stream = [System.Net.Sockets.TcpClient]::new('google.com', 80).GetStream()
'@

[string[]] $allowedCommands  =  'Write-Host'
[string[]] $allowedVaribales =  ''

try {
    $scriptblock = [scriptblock]::Create($String)
    $scriptblock.CheckRestrictedLanguage(
        $allowedCommands,
        $allowedVaribales,
        $false # Argument to allow Environmental Variables
    )
    & $scriptblock
}
catch {
    Write-Warning $_.Exception.Message
}
Run Code Online (Sandbox Code Playgroud)

另一种选择是使用Mode在运行空间中运行表达式。这个功能可以让事情变得非常简单。ConstrainedLanguage

using namespace System.Management.Automation.Language
using namespace System.Collections.Generic
using namespace System.Management.Automation.Runspaces

function Invoke-ConstrainedExpression {
    [CmdletBinding(DefaultParameterSetName = 'ScriptBlock')]
    param(
        [Parameter(ParameterSetName = 'Command', Mandatory, ValueFromPipeline, Position = 0)]
        [string] $Command,

        [Parameter(ParameterSetName = 'ScriptBlock', Mandatory, Position = 0)]
        [scriptblock] $ScriptBlock,

        [Parameter()]
        [Management.Automation.PSLanguageMode] $LanguageMode = 'ConstrainedLanguage',

        # When using this switch, the function inspects the AST to find any variable
        # not being an assigned one in the expression, queries the local state to find
        # it's value and injects that variable to the Initial Session State of the Runspace.
        [Parameter()]
        [switch] $InjectLocalVariables
    )

    process {
        try {
            $Expression = $ScriptBlock
            if($PSBoundParameters.ContainsKey('Command')) {
                $Expression = [scriptblock]::Create($Command)
            }

            # bare minimum for the session state
            $iss = [initialsessionstate]::CreateDefault2()
            # set `ContrainedLanguage` for this session
            $iss.LanguageMode = $LanguageMode

            if($InjectLocalVariables.IsPresent) {
                $ast = $Expression.Ast
                $map = [HashSet[string]]::new([StringComparer]::InvariantCultureIgnoreCase)
                $ast.FindAll({ $args[0] -is [AssignmentStatementAst] }, $true).Left.Extent.Text |
                    ForEach-Object { $null = $map.Add($_) }

                $variablesToInject = $ast.FindAll({
                    $args[0] -is [VariableExpressionAst] -and
                    -not $map.Contains($args[0].Extent.Text)
                }, $true).VariablePath.UserPath

                foreach($var in $variablesToInject) {
                    $value = $ExecutionContext.SessionState.PSVariable.GetValue($var)
                    $entry = [SessionStateVariableEntry]::new($var, $value, '')
                    $iss.Variables.Add($entry)
                }
            }

            # create the PS Instance and add the expression to invoke
            $ps = [powershell]::Create($iss).AddScript($Expression)
            # invoke the expression
            [Collections.Generic.List[object]] $stdout = $ps.Invoke()
            $streams = $ps.Streams
            $streams.PSObject.Properties.Add([psnoteproperty]::new('Success', $stdout))
            $streams
        }
        finally {
            if($ps) { $ps.Dispose() }
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

现在我们可以使用约束语言测试表达式:

Invoke-ConstrainedExpression {
    Write-Host 'Starting script'
    [System.Net.WebClient]::new().DownloadString($uri) | iex
    'Hello world!'
}
Run Code Online (Sandbox Code Playgroud)

输出如下所示:

Success     : {Hello world!}
Error       : {Cannot create type. Only core types are supported in this language mode.}
Progress    : {}
Verbose     : {}
Debug       : {}
Warning     : {}
Information : {Starting script}
Run Code Online (Sandbox Code Playgroud)

开发博客文章:PowerShell 约束语言模式有一些不错的信息,绝对值得一读。