英文:
How verify and use two arguments are set so don't get garbage
问题
I'm using arguments for a PowerShell script, but I found that if the second one isn't set, it's getting garbage, although it's possible I'm doing something wrong, since I'm having trouble finding examples with two passed-in arguments. How can I verify that both are set?
This script is called from a very old perl script as shown:
#`"C:\\Program Files\\PowerShell\\\pwsh.exe" -NoProfile -noninteractive -ExecutionPolicy bypass -Command "\\\\wserverp01\\kiosksupport\\Retailer_DeviceSN\\MoveSNToSprdsht_1.0.ps1 $service_report_xls"`;
In my script, MoveSNToSprdsht_1.0.ps1:
$out_pth = ""
$outFilePathExcel_pl = ""
$outFilePathExcel_pl = $Args[0]
$out_pth = $Args[1] #this is blob scan output dir that we look for the correct date file in
Write-Host "new tab will go to:$($outFilePathExcel_pl)"
Write-Host "Will get files from:$($out_pth)" #this had garbage in it, like terminal output from something I ran yesterday that's unrelated
I was thinking maybe I'm not supposed to use $Args[1], and found [this example][1], but it doesn't say what to do in the script with -arg1 and -arg2. I'm using VisualStudioCode to run the PowerShell to test it for now so it's possible I'm executing it from the VSC command line incorrectly as well. When I used the pasted perl line from the old perl script, it worked ok with the first parameter but I've added the second parameter now.
I haven't found in a search how to verify the script arguments are actually set. I tried checking against an empty string, and that didn't work. Something had filled Arg[1] with the garbage, so it failed the check for an empty string.
Update:
So if I used cmdletbinding, would this be good program structure, and would the program be run the normal way?
[cmdletbinding()]
Param ( [Parameter(Mandatory)][string]$outFilePathExcel_pl, [Parameter(Mandatory)][string]$out_pth="\\wserverp01\support\Retailer_SN\OutputSprdsht\")
#and the rest of the program...
Get-ChildItem $out_pth | Foreach-Object {$lastupdatetime=$_.LastWriteTime;$nowtime = get-date; if (($nowtime - $lastupdatetime).totalhours -le 72) {write-host "here2";$excel_File_from = $_.Name;write-host $_.name}}
..
Update2:
Hopefully I'm calling the PowerShell script correctly, below, per comments.
my $resultPS = `"C:\\Program Files\\PowerShell\\\pwsh.exe" -NoProfile -noninteractive -ExecutionPolicy bypass -File "\\\\wserverp01\\support\\Retailer_SN\\MoveSNToSprdsht_1.0.ps1" "-outFilePathExcel_pl $service_report_xls" "-out_pth $cvs_blob_scan_dir"`;
Calling updated PowerShell script:
[cmdletbinding()]
param( [Parameter(Mandatory)][string]$outFilePathExcel_pl, [Parameter()][string]$out_pth="\\wserverp01\support\Retailer_SN\OutputSprdsht\")
Start-Transcript -path '\\wserverp01\support\Retailer_SN\Logs\MoveSNToSprdsht.log'
#get file location from parameter so put sn tab there
Write-Host "new tab will go to:$($outFilePathExcel_pl)"
Write-Host "Will get scan files from:$($out_pth)"
#make sure params are valid paths; non-terminating error if invalid
if(Test-Path $outFilePathExcel_pl)
{
Write-Host "path for $outFilePathExcel_pl looks good"
}
else
{
Write-Error "path for $outFilePathExcel_pl invalid"
}
if(Test-Path $out_pth)
{
Write-Host "path for $out_pth looks good"
}
else
{
Write-Error "path for $outFilePathExcel_pl invalid"
}
Get-ChildItem $out_pth | Foreach-Object {$lastupdatetime=$_.LastWriteTime;$nowtime = get-date; if (($nowtime - $lastupdatetime).totalhours -le 72) {write-host "here2";$excel_File_from = $_.Name;write-host $_.name}}
Update3:
For some reason when I use the named parameters from perl and use them from the PowerShell, I'm getting:
Cannot bind argument to parameter 'Path' because it is an empty string.
when I try to use the variable. Is there a problem with my syntax?
From perl:
my $resultPS = `"C:\\Program Files\\PowerShell\\\pwsh.exe" -NoProfile -noninteractive -ExecutionPolicy bypass -File "\\\\wserverp01\\support\\Retailer_SN\\MoveSNToSprdsht_1.0.ps1" -outFilePathExcel_pl "$service_report_xls" -out_pth "$retailer_blob_scan_dir"`;
Then in MoveSNToSprdsht_1.0.ps1:
[cmdletbinding()]
param( [Parameter(Mandatory)][string]$outFilePathExcel_pl, [Parameter()][string]$out_pth="\\wserverp01\support\Retailer_SN\OutputSprdsht\")
Start-Transcript -path '\\wserverp01\support\Retailer_SN\Logs\MoveSNToSprdsht.log'
#get file location from parameter so put sn tab there
Write-Host "new tab will go to:$($outFilePathExcel_pl)" #need to use below instead of $outFilePathExcel
Write-Host "Will get blob scan files from:$($out_pth)"
#make sure params are valid paths; non-terminating error if invalid
if(Test-Path $outFilePathExcel_pl)
{
Write-Host "path for $outFilePathExcel_pl looks good"
}
else
{
Write-Error "path for $outFilePathExcel_pl invalid"
}
if(Test-Path $out_pth)
{
Write-Host "path for $out_pth looks good"
}
else
{
Write-Error "path for $out_pth invalid"
}
[System.String] $excel_File_from = "
<details>
<summary>英文:</summary>
I'm using arguments for a PowerShell script, but I found that if the second one isn't set, it's getting garbage, although it's possible I'm doing something wrong, since I'm having trouble finding examples with two passed in arguments. How can I verify that both are set?
This script is called from a very old perl script as shown:
#`"C:\\Program Files\\PowerShell\\7\\pwsh.exe" -NoProfile -noninteractive -ExecutionPolicy bypass -Command "\\\\wserverp01\\kiosksupport\\Retailer_DeviceSN\\MoveSNToSprdsht_1.0.ps1 $service_report_xls"`;
In my script, MoveSNToSprdsht_1.0.ps1:
$out_pth = ""
$outFilePathExcel_pl = ""
$outFilePathExcel_pl = $Args[0]
$out_pth = $Args[1] #this is blob scan output dir that we look for correct date file in
Write-Host "new tab will go to:$($outFilePathExcel_pl)"
Write-Host "Will get files from:$($out_pth)" #this had garbage in it, like terminal output from something I ran yesterday that's unrelated
I was thinking maybe I'm not supposed to use $Args[1], and found [this example][1], but it doesn't say what to do in the script with -arg1 and -arg2. I'm using VisualStudioCode to run the PowerShell to test it for now so it's possible I'm executing it from the VSC command line incorrectly as well. When I used the pasted perl line from the old perl script, it worked ok with the first parameter but I've added the second parameter now.
I haven't found in a search how to verify the script arguments are actually set. I tried checking against empty string and that didn't work. Something had filled Arg[1] with the garbage so it failed the check for empty string.
**Update:**
So if I used cmdletbinding, would this be good program structure, and would the program be run the normal way?
[cmdletbinding()]
Param ( [Parameter(Mandatory)][string]$outFilePathExcel_pl, [Parameter(Mandatory)][string]$out_pth="\\wserverp01\support\Retailer_SN\OutputSprdsht\")
#and the rest of the program...
Get-ChildItem $out_pth | Foreach-Object {$lastupdatetime=$_.LastWriteTime;$nowtime = get-date; if (($nowtime - $lastupdatetime).totalhours -le 72) {write-host "here2";$excel_File_from = $_.Name;write-host $_.name}}
..
**Update2:**
Hopefully I'm calling the powershell script correctly, below, per comments.
my $resultPS = `"C:\\Program Files\\PowerShell\\7\\pwsh.exe" -NoProfile -noninteractive -ExecutionPolicy bypass -File "\\\\wserverp01\\support\\Retailer_SN\\MoveSNToSprdsht_1.0.ps1" "-outFilePathExcel_pl $service_report_xls" "-out_pth $cvs_blob_scan_dir"`;
Calling updated powershell script:
[cmdletbinding()]
param( [Parameter(Mandatory)][string]$outFilePathExcel_pl, [Parameter()][string]$out_pth="\\wserverp01\support\Retailer_SN\OutputSprdsht\")
Start-Transcript -path '\\wserverp01\support\Retailer_SN\Logs\MoveSNToSprdsht.log'
#get file location from parameter so put sn tab there
Write-Host "new tab will go to:$($outFilePathExcel_pl)"
Write-Host "Will get scan files from:$($out_pth)"
#make sure params are valid paths; non-terminating error if invalid
if(Test-Path $outFilePathExcel_pl)
{
Write-Host "path for $outFilePathExcel_pl looks good"
}
else
{
Write-Error "path for $outFilePathExcel_pl invalid"
}
if(Test-Path $out_pth)
{
Write-Host "path for $out_pth looks good"
}
else
{
Write-Error "path for $outFilePathExcel_pl invalid"
}
Get-ChildItem $out_pth | Foreach-Object {$lastupdatetime=$_.LastWriteTime;$nowtime = get-date; if (($nowtime - $lastupdatetime).totalhours -le 72) {write-host "here2";$excel_File_from = $_.Name;write-host $_.name}}
**Update3:**
For some reason when I use the named parameters from perl and use them from the powershell, I'm getting
Cannot bind argument to parameter 'Path' because it is an empty string.
when I try to use the variable. Is there a problem with my syntax?
from perl:
my $resultPS = `"C:\\Program Files\\PowerShell\\7\\pwsh.exe" -NoProfile -noninteractive -ExecutionPolicy bypass -File "\\\\wserverp01\\support\\Retailer_SN\\MoveSNToSprdsht_1.0.ps1" -outFilePathExcel_pl "$service_report_xls" -out_pth "$retailer_blob_scan_dir"`;
(where the variables are set from an ini file and passed to the script as the parameters, printout before the powershell call look good in perl)
Then in MoveSNToSprdsht_1.0.ps1:
[cmdletbinding()]
param( [Parameter(Mandatory)][string]$outFilePathExcel_pl, [Parameter()][string]$out_pth="\\wserverp01\support\Retailer_SN\OutputSprdsht\")
Start-Transcript -path '\\wserverp01\support\Retailer_SN\Logs\MoveSNToSprdsht.log'
#get file location from parameter so put sn tab there
Write-Host "new tab will go to:$($outFilePathExcel_pl)" #need to use below instead of $outFilePathExcel############################
Write-Host "Will get blob scan files from:$($out_pth)"
#make sure params are valid paths; non-terminating error if invalid
if(Test-Path $outFilePathExcel_pl)
{
Write-Host "path for $outFilePathExcel_pl looks good"
}
else
{
Write-Error "path for $outFilePathExcel_pl invalid"
}
if(Test-Path $out_pth)
{
Write-Host "path for $out_pth looks good"
}
else
{
Write-Error "path for $out_pth invalid"
}
[System.String] $excel_File_from = ""
############## hours - 72 hours is ok for now so we don't cut it too close for file timestamp for scan..scan run on weekend, use Monday:
Get-ChildItem $out_pth | Foreach-Object {$lastupdatetime=$_.LastWriteTime;$nowtime = get-date; if (($nowtime - $lastupdatetime).totalhours -le 72) {write-host "here2";$excel_File_from = $_.Name;write-host $_.name}}
Maybe I need curly brackets below the cmdlet binding? It the error is complaining about using the empty parameter, not wrong formatting though.
[1]: https://stackoverflow.com/questions/47051466/call-powershell-script-with-multiple-args-from-command-line
</details>
# 答案1
**得分**: 1
* 在您的 Perl 命令行中,`$service_report_xls` 是一个 _Perl_ 变量,会被字符串扩展。为了*健壮地*传递它,将其括在*嵌入的* `"..."` 中,需要 `\\"...\\"`(原文如此):
```perl
`"C:\\Program Files\\PowerShell\\7\\pwsh.exe" -NoProfile -noninteractive -ExecutionPolicy bypass -Command "\\\\wserverp01\\kiosksupport\\Retailer_DeviceSN\\MoveSNToSprdsht_1.0.ps1 \\"$service_report_xls\\""`;
- 然而,即使这样也可能使您的参数受到不希望的解释,因为使用了
-Command
PowerShell CLI 参数。对于执行 脚本文件 (*.ps1
),更好的选择是使用-File
参数,它接受将逐字传递的单独参数(有关何时使用-Command
vs.-File
的指导,请参阅此答案):
`"C:\\Program Files\\PowerShell\\7\\pwsh.exe" -NoProfile -NonInteractive -ExecutionPolicy Bypass -File "\\\\wserverp01\\kiosksupport\\Retailer_DeviceSN\\MoveSNToSprdsht_1.0.ps1" "$service_report_xls"`;
- 为确保不会传递意外的参数给您的 PowerShell 脚本(.ps1),将您的脚本定义为高级脚本,这需要正式声明参数并使用
[CmdletBinding()]
属性;高级脚本和函数只接受与正式声明的参数绑定的参数;例如:
[CmdletBinding()] # 使脚本成为高级脚本。
param(
# 强制,第一个位置参数
[Parameter(Mandatory)] # 确保始终传递参数。
[string] $outFilePathExcel_pl,
# 可选,第二个位置参数,带有默认值。
[string] $out_pth = '...'
)
# ...
注意:由于已声明的参数也可以通过名称绑定(最好如此,以便更好地理解概念),例如...\MoveSNToSprdsht_1.0.ps1 -outFilePathExcel_pl c:\some\file.xlsx
,建议使用更具描述性的参数名称。
英文:
- In your Perl command line,
$service_report_xls
is a Perl variable that gets string-expanded. To pass it robustly, enclose it in embedded"..."
, which requires\\"...\\"
(sic):
`"C:\\Program Files\\PowerShell\\7\\pwsh.exe" -NoProfile -noninteractive -ExecutionPolicy bypass -Command "\\\\wserverp01\\kiosksupport\\Retailer_DeviceSN\\MoveSNToSprdsht_1.0.ps1 \\"$service_report_xls\\""`;
- However, even that can subject your arguments to unwanted interpretation, due to use of the
-Command
PowerShell CLI parameter. For execution of a script file (*.ps1
) the better option is to use the-File
parameter, which accepts separate arguments that are passed verbatim (for guidance on when to use-Command
vs.-File
, see this answer):
`"C:\\Program Files\\PowerShell\\7\\pwsh.exe" -NoProfile -NonInteractive -ExecutionPolicy Bypass -File "\\\\wserverp01\\kiosksupport\\Retailer_DeviceSN\\MoveSNToSprdsht_1.0.ps1" "$service_report_xls"`;
- To ensure that no unexpected arguments are passed to your PowerShell script (
*.ps1
), make your script an advanced one, which requires formally declaring parameters and using the[CmdletBinding()]
attribute; advanced scripts and functions only accept arguments that bind to formally declared parameters; e.g.:
[CmdletBinding()] # Make the script an advanced one.
param(
# Mandatory, 1st positional parameter
[Parameter(Mandatory)] # Make sure an argument is always passed.
[string] $outFilePathExcel_pl,
# Optional, 2nd positional parameter with default value.
[string] $out_pth = '...'
)
# ...
Note: Since declared parameters can also be bound by name (preferably so, for conceptual clarity) - e.g. ...\MoveSNToSprdsht_1.0.ps1 -outFilePathExcel_pl c:\some\file.xlsx
- it's better to use more descriptive parameter names.
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论