微信公众号搜"智元新知"关注
微信扫一扫可直接关注哦!

输出文件时使用Powershell环境变量作为字符串

如何解决输出文件时使用Powershell环境变量作为字符串

我正在使用 Get-WindowsAutopilotInfo 生成计算机的序列号和哈希码,并将该信息导出为 CSV。

这是我通常使用的代码

new-item "c:\Autopilot_Export" -type directory -force

Set-Location "C:\Autopilot_Export"

Get-WindowsAutopilotInfo.ps1 -OutputFile Autopilot_CSV.csv

Robocopy C:\Autopilot_Export \\Zapp\pc\Hash_Exports /copyall

这会将名为“Autopilot_CSV.csv”的 CSV 文件输出C:\Autopilot_Export 目录,然后 Robocopy 将其复制到上面列出的 Hash_Exports 文件夹内的网络共享驱动器。在上面的代码中,如果我手动输入“test”、“123”、“ABC”等并替换“Autopilot_CSV”,它也会在所有这些名称输出一个 CSV。所以看起来 Get-WindowsAutopilotInfo 将创建一个 CSV 文件并使用您传递给它的任何字符串保存文件名。太好了。

但是,我在多台不同的计算机上运行这个脚本,我希望导出的 CSV 被命名为它运行的机器所独有的名称,这样我就可以在复制后轻松识别它。我试图将环境变量 $env:computername 的值作为 CSV 的字符串输入传递,但它不起作用。

这是我尝试使用的代码

new-item "c:\Autopilot_Export" -type directory -force

Set-Location "C:\Autopilot_Export"

Get-WindowsAutopilotInfo.ps1 -OutputFile $env:computername.csv

Robocopy C:\Autopilot_Export C:\Users\danieln\Desktop /copyall

代码根本不会生成 CSV 文件。为什么不呢?

我是否只是对 Powershell 中如何使用环境变量有基本的误解? $env:computername 似乎返回计算机名称的字符串,但我无法将其传递到 Get-WindowsAutopilotInfo 并保存它,但是如果我手动输入字符串作为输入,它工作.

我还尝试将其设置为变量 $computername = [string]$env:computername 并仅在 .CSV 之前传入 $computername 并且这似乎也不起作用。根据文档,环境变量显然已经是字符串了。

我错过了什么吗?

谢谢!

解决方法

js2010's answer 显示了有效的解决方案:使用 "..."-quoting,即 expandable string explicitly

命令参数周围使用"..." 显式是一个好习惯,这些命令参数包含变量的字符串引用(例如 "$HOME/projects")或子表达式(例如 "./folder/$(Get-Date -Format yyyy-MM)"

虽然这样的复合字符串参数一般需要双引号[1] - 因为它们隐式 被视为被 "..." 封闭 - 在某些情况下,他们,并且何时他们做的并不明显,因此很难记住:

This answer 详细说明了令人惊讶的复杂规则,但这里有两个值得注意的陷阱

  • 如果复合参数子表达式($(...))开头,则其输出将作为单独的参数传递;例如Write-Output $(Get-Location)/folder两个 参数传递给 Write-Output$(Get-Location) 和文字 /folder

    的结果
  • 如果一个复合参数一个变量引用后面跟着语法上的样子要么 (a) a 属性访问(例如,$PSVersionTable.PsVersion)或(b)一个方法调用(例如,$PSHome.Tolower())它是执行的,即作为表达式(而不是被视为变量引用后跟文字部分)。

    • 旁白#1:这样的参数不一定是字符串,而是属性值或方法调用返回值碰巧是什么数据类型。

    • 旁白#2:复合字符串带引号的字符串(无论是单引号还是双引号) > 工作,因为开头的引用字符串也被认为是一个表达式,就像属性访问和方法调用一样,因此后面的内容再次作为单独的参数传递。因此,如果复合字符串以 unquoted 子字符串或非表达式变量引用开头,则您只能拥有由带引号和不带引号的子字符串混合组成的复合字符串。[2]上>

后者是在这种情况下发生了什么

  • 未加引号 $env:computername.csv 被解释为尝试访问存储在 (环境)变量 csv,并且由于存储在那里的 $env:computername 实例没有 [string] 属性,因此表达式计算为 csv

  • 通过强制 PowerShell 将此值解释为通过 $null 的可扩展字符串,通常的 interpolation rules 适用,这意味着 "..." 是确实被视为文字(因为属性访问需要在可扩展字符串中使用 .csv)。


[1] 包含元字符(例如空格)的字符串需要引用
对于要逐字处理的值,$(...) 引用是更好的选择(有关 PowerShell 字符串文字的概述,请参阅 this answer 的底部部分)。
此外,既不使用双引号也不使用单引号和单独 '...' 转义元字符是另一种选择(例如 `.

[2] 例如,Write-Output C:\Program` FilesWrite-Output a"b`t"'`c' 按预期工作,而 Write-Output $HOME"b`t"'`c'Write-Output "b`t"'`c' 则不然(后两个都通过 3 个参数)。解决方法是根据需要使用带有内部 Write-Output $HOME.Length"b`t"'`c' 转义的 single "..." 字符串(例如 `),或者使用带有 {{ 1}} 括在 Write-Output "${HOME}b`t``c" 中(例如 +

,

双引号似乎有效。冒号在 powershell 参数中很特殊。

echo hi | set-content "$env:computername.csv"

dir


    Directory: C:\users\me\foo


Mode                 LastWriteTime         Length Name
----                 -------------         ------ ----
-a----         2/11/2021   1:02 PM              4 COMP001.csv

冒号是特殊的。例如在开关参数中:

get-childitem -force:$true

实际上,它正在尝试查找名为 csv 的属性:

echo hi | Set-Content  $env:COMPUTERNAME.length
dir


    Directory: C:\Users\me\foo


Mode                 LastWriteTime         Length Name
----                 -------------         ------ ----
-a----         2/11/2021   3:04 PM              4 8
,

基本上传递一个字符串而不是变量:

write-host $env:computername.csv
# output: (no output - looking for a variable called "computername.csv" instead of "computername")

尝试以下语法:

$filename = "$($env:computername).csv"
write-host $filename 

# output: MYPCNAME.csv

版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。