不使用 Invoke-Expression 扩展字符串 [英] Expand string without Invoke-Expression

查看:35
本文介绍了不使用 Invoke-Expression 扩展字符串的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

想象一下下面的代码:

# 脚本开始$WelcomeMessage = "你好 $UserName,今天是 $($Date.DayOfWeek)"....# 100 行其他函数,还有什么不.....功能问候用户{$Username = Get-UserNameFromSomewhereFancy$Date = Get-DateFromSomewhereFancy$欢迎信息}

这是一个非常基本的例子,但它试图展示的是一个脚本,其中有一个 $WelcomeMessage,运行脚本的人可以在脚本的顶部设置它并控制如何/显示的消息是什么.

第一件事是:为什么要做这样的事情?好吧,如果您将脚本传递给多个人,他们可能想要不同的消息.也许他们不喜欢 $($Date.DayOfWeek) 并且想要获得完整的日期.也许他们不想显示用户名,无论如何.

第二,为什么把它放在脚本的顶部?简单.如果您的脚本中有 1000 行,并且此类消息遍布整个脚本,那么人们查找和更改这些消息将是一场噩梦.我们已经为静态消息以本地化字符串和其他东西的形式这样做了,所以这不是什么新鲜事,除了其中的可变部分.

那么,现在该问题了.如果您运行该代码并调用 Greet-User(假设用于检索用户名和日期的函数/cmdlet 实际存在并返回正确的内容...)Greet-User 将始终return 你好,今天是.

这是因为当您在脚本顶部声明字符串时,当 $UserName$Date 对象都没有值时,字符串会被扩展.

一个潜在的解决方法是用单引号创建字符串,并使用 Invoke-Expression 来扩展它们.但是因为有空格,所以有点乱.即:

$WelcomeMessage = '你好 $env:USERNAME'调用表达式 $WelcomeMessage

由于空间原因,这会引发错误,为了使其正常工作,必须这样声明:

$WelcomeMessage = '你好 $env:USERNAME'$InvokeExpression = "`"$WelcomeMessage`""

凌乱...

此外,还有一个问题是代码注入的形式.由于我们允许用户在没有指定边界的情况下编写他们自己的欢迎消息,有什么可以防止他们输入诸如...

$WelcomeMessage 'Hello $([void] (Remove-Item C:\Windows -Force -Recurse))'

(是的,我知道这不会删除所有内容,但这是一个示例)

当然这是一个脚本,如果他们可以修改该字符串,他们也可以修改脚本上的所有其他内容,但是虽然我举的例子是有人恶意利用脚本的性质,但也可能发生有人不小心将一些东西放入字符串中,最终会产生不必要的后果.

所以...必须有一种不使用 Invoke-Expression 的更好方法,我只是不能完全理解,因此将不胜感激 :)

解决方案

将变量嵌入字符串并不是创建动态文本的唯一方法,我会这样做:

$WelcomeMessage = '你好 {0},今天是 {1}'# 100 行其他函数,还有什么不...功能问候用户{$Username = Get-UserNameFromSomewhereFancy$Date = Get-DateFromSomewhereFancy$WelcomeMessage -f $用户名,$日期}

Imagine the following code:

# Script Start
$WelcomeMessage = "Hello $UserName, today is $($Date.DayOfWeek)"

..
..
# 100 lines of other functions and what not...
..

function Greet-User
{
    $Username = Get-UserNameFromSomewhereFancy
    $Date = Get-DateFromSomewhereFancy

    $WelcomeMessage
}

This is a very basic example, but what it tries to show is a script where there is a $WelcomeMessage that the person running the script can set at the top of the script and controls how/what the message displayed is.

First thing's first: why do something like this? Well, if you're passing your script around to multiple people, they might want different messages. Maybe they don't like $($Date.DayOfWeek) and want to get the full date. Maybe they don't want to show the username, whatever.

Second, why put it at the top of the script? Simplicity. If you have 1000 lines in your script and messages like these spread all over the script, it makes it a nightmare for people to find and change these messages. We already do that for static messages, in the form of localized strings and stuff, so this is nothing new, except for the variable parts in it.

So, now to the issue. If you run that code and invoke Greet-User (assuming the functions/cmdlets for retrieving username and date actually exist and return something proper...) Greet-User will always return Hello , today is.

This is because the string is expanded when you declare it, at the top of the script, when neither $UserName nor $Date objects have a value.

A potential workaround would be to create the strings with single quotes, and use Invoke-Expression to expand them. But because of the spaces, that gets a bit messy. I.e.:

$WelcomeMessage = 'Hello $env:USERNAME'
Invoke-Expression $WelcomeMessage

This throws an error because of the space, to get it to work properly it would have to be declared as such:

$WelcomeMessage = 'Hello $env:USERNAME'
$InvokeExpression = "`"$WelcomeMessage`""

Messy...

Also, there's another problem in the form of code injection. Since we're allowing the user to write their own welcome message with no bounds specified, what's to prevent them from putting in something like...

$WelcomeMessage 'Hello $([void] (Remove-Item C:\Windows -Force -Recurse))'

(Yes, I know this will not delete everything but it is an example)

Granted this is a script and if they can modify that string they can also modify everything else on the script, but whereas the example I gave was someone maliciously taking advantage of the nature of the script, it can also happen that someone accidentally puts something in the string that ends up having unwanted consequences.

So... there's got to be a better way without the use of Invoke-Expression, I just can't quite thing of one so help would be appreciated :)

解决方案

Embedding variables into strings is not the only way to create dynamic text, the way I would do it is like this:

$WelcomeMessage = 'Hello {0}, today is {1}'

# 100 lines of other functions and what not...

function Greet-User
{
    $Username = Get-UserNameFromSomewhereFancy
    $Date = Get-DateFromSomewhereFancy

    $WelcomeMessage -f $Username, $Date
}

这篇关于不使用 Invoke-Expression 扩展字符串的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆