【问题标题】:Using Powershell environmental variables as strings when outputting files输出文件时使用 Powershell 环境变量作为字符串
【发布时间】:2021-05-15 12:18:27
【问题描述】:

我正在使用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 ,但这似乎也不起作用。根据文档,环境变量显然已经是字符串。

我错过了什么吗?

谢谢!

【问题讨论】:

    标签: powershell csv scripting environment-variables export-to-csv


    【解决方案1】:

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

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

    虽然这种复合字符串参数一般不需要双引号[1] - 因为它们是隐式的 将它们视为"..."-enclosed - 在某些情况下,它们,而它们不明显,因此很难记住:

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

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

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

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

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

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

    • 未引用 $env:computername.csv 被解释为试图访问 在(环境)变量 $env:computername 中存储的对象上名为 csv 的属性/strong>,并且由于存储在那里的[string] 实例没有csv 属性,因此表达式计算为$null

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


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

    [2] 例如,Write-Output a"b`t"'`c'Write-Output $HOME"b`t"'`c' 按预期工作,而 Write-Output "b`t"'`c'Write-Output $HOME.Length"b`t"'`c' 不能(后两者各传递 3 个参数)。解决方法是使用 single "..." 字符串和内部 `-根据需要转义(例如 Write-Output "${HOME}b`t``c"),或者使用包含在 (...) 中的 + 的字符串连接表达式(例如Write-Output ($HOME + "b`t" + '`c')

    【讨论】:

      【解决方案2】:

      双引号似乎有效。冒号在 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
      

      【讨论】:

      • 非常感谢!也许我只是不完全了解环境变量以及冒号在 Powershell 中的工作原理。我会想,既然$env:comptername 的值已经是一个字符串,它会这样工作。
      • 双引号确实是正确的解决方案,但这样做的需要与:(冒号)的使用无关。这里需要双引号的原因是$env:computername.csv 被解释为试图访问存储在变量$env:computername 中的对象上名为csv的属性
      • @mklement0 是的。
      【解决方案3】:

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

      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
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2014-03-10
        • 1970-01-01
        • 1970-01-01
        • 2016-01-21
        • 2017-02-02
        • 1970-01-01
        • 2015-01-29
        • 1970-01-01
        相关资源
        最近更新 更多