问题
I am using Get-WindowsAutopilotInfo to generate a computer's serial number and a hash code and export that info as a CSV.
Here is the code I usually use:
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
This outputs a CSV file named "Autopilot_CSV.csv" to the C:\Autopilot_Export
directory and then Robocopy copies it to the Network Share drive inside of the Hash_Exports folder listed above. In the above code, if I manually type in "test", "123", "ABC", etc. and replace "Autopilot_CSV" it will output a CSV under all of those names as well. So it looks like Get-WindowsAutopilotInfo will create a CSV file and save the file name with whatever string you pass into it. Great.
However, I am running this script on multiple different computers and I would like the exported CSV to be named something unique to the machine it is running on so I can easily identify it once it's copied. I am trying to pass the value of the environmental variable $env:computername
as a string input for the CSV and it isn't working.
Here's the code I'm trying to use:
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
This code does not generate the CSV file at all. Why not?
Do I just have a basic misunderstanding of how environmental variables are used in Powershell? $env:computername
appears to return a string of the computer's name, but I cannot pass it into Get-WindowsAutopilotInfo and have it save, but it will work if I manually type a string in as the input.
I have also tried setting it to a variable $computername = [string]$env:computername
and just passing $computername
in before the .CSV and that doesn't appear to work either. And per the docmentation, environmental variables are apparently already strings.
Am I missing something?
Thanks!
回答1:
Doublequoting seems to work. The colon is special in powershell parameters.
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
The colon is special. For example in switch parameters:
get-childitem -force:$true
Actually, it's trying to find a property named 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
回答2:
js2010's answer shows the effective solution: use "..."
-quoting, i.e. an expandable string explicitly.
It is a good habit to form to use "..."
explicitly around command arguments that are strings containing variable references (e.g. "$HOME/projects"
) or subexpressions (e.g., "./folder/$(Get-Date -Format yyyy-MM)"
)
While such compound string arguments generally do not require double-quoting[1] - because they are implicitly treated as if they were "..."
-enclosed - in certain cases they do, and when they do is not obvious and therefore hard to remember:
This answer details the surprisingly complex rules, but here are two notable pitfalls:
If a compound argument starts with a subexpression (
$(...)
), its output is passed as a separate argument; e.g.Write-Output $(Get-Location)/folder
passes two arguments toWrite-Output
: the result of$(Get-Location)
and literal/folder
If a compound argument starts with a variable reference and is followed by what syntactically looks like either (a) a property access (e.g.,
$PSVersionTable.PsVersion
) or (b) a method call (e.g.,$PSHome.Tolower()
) it is executed as just that, i.e. as an expression (rather than being considered a variable reference followed by a literal part).Aside #1: Such an argument then isn't necessarily a string, but whatever data type the property value or method-call return value happens to be.
Aside #2: A compound string that starts with a quoted string (whether single- or double-quoted) does not work, because the quoted string at the start is also considered an expression, like property access and method calls, so that what comes after is again passed as separate argument(s). Therefore, you can only have a compound strings consisting of a mix of quoted and unquoted substrings if the compound string starts with an unquoted substring or a non-expression variable reference.[2]
The latter is what happened in this case:
Unquoted
$env:computername.csv
was interpreted as an attempt to access a property namedcsv
on the object stored in (environment) variable$env:computername
, and since the[string]
instance stored there has nocsv
property, the expression evaluated to$null
.By forcing PowerShell to interpret this value as an expandable string via
"..."
, the usual interpolation rules apply, which means that the.csv
is indeed treated as a literal (because property access requires use of$(...)
in expandable strings).
[1] Quoting is required for strings that contain metacharacters such as spaces.
For values to be treated verbatim, '...'
quoting is the better choice (see the bottom section of this answer for an overview of PowerShell string literals).
Also, using neither double- nor single-quoting and individually `
-escaping metacharacters is another option (e.g. Write-Output C:\Program` Files
.
[2] For instance, Write-Output a"b`t"'`c'
and Write-Output $HOME"b`t"'`c'
work as intended, whereas Write-Output "b`t"'`c'
and Write-Output $HOME.Length"b`t"'`c'
do not (the latter two each pass 3 arguments). The workaround is to either use a single "..."
string with internal `
-escaping as necessary (e.g. Write-Output "${HOME}b`t``c"
) or to use string-concatenation expression with +
enclosed in (...)
(e.g. Write-Output ($HOME + "b`t" + '`c')
)
回答3:
Basically pass it a string rather than the variable:
write-host $env:computername.csv
# output: (no output - looking for a variable called "computername.csv" instead of "computername")
Try the following syntax:
$filename = "$($env:computername).csv"
write-host $filename
# output: MYPCNAME.csv
来源:https://stackoverflow.com/questions/66160137/using-powershell-environmental-variables-as-strings-when-outputting-files