在今天的测试中,我遇到了一个意外的问题,我不明白为什么会这样。以下是我用来复制问题的代码。这只是大型项目的一小部分。
如果有帮助的话,可以在Windows 10 Build 1709上进行测试
PS1文件和BAT文件的名称相同。
导致错误的方式
Right-Click - Run with PowerShell
运行PS1文件将导致错误PowerShell ISE
,然后打开/运行脚本会导致错误避免错误的方法
PowerShell ISE
,然后打开/运行脚本将不会引起错误Script:
,无论脚本如何执行,都不会不会导致错误Admin
的身份运行,它将在VSCode之外启动PowerShell.exe
并正常工作-
为什么在函数中的变量前面有Script:
?这是我可以在函数中设置要在函数外部使用的变量的唯一方法。这篇文章中未列出的其他25个左右的变量没有问题,但是它们没有像设置这两个变量那样被修改。
问题
Admin
模式运行ISE,它将起作用?有些事情没有道理,我无法指出。
这是错误
由于变量已优化,因此无法覆盖变量NetFX3。尝试使用New-Variable或Set-Variable cmdlet(不带任何别名),或点源用于设置变量的命令。 在C:\ Users \ a502690530 \ Desktop \ Testing2.ps1:14 char:5 + [string] $ Script:NetFX3 = $ BAT_Files_Path +“ NetFX3.zip” + ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ ~~~~~~~~~~~ + CategoryInfo:WriteError:(NetFX3:String)[],SessionStateUnauthorizedAccessException + FullyQualifiedErrorId:VariableNotWritableRare
由于变量已优化,因此无法覆盖变量Power_Plan。尝试使用New-Variable或 Set-Variable cmdlet(不带任何别名),或者使用点源来设置变量的命令。 在C:\ Users \ a502690530 \ Desktop \ Testing2.ps1:15 char:5 + [string] $ Script:Power_Plan = $ BAT_Files_Path +“ Power_Plan.zip” + ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ ~~~~~~~~~~~~~~ + CategoryInfo:WriteError:(Power_Plan:String)[],SessionStateUnauthorizedAccessException + FullyQualifiedErrorId:VariableNotWritableRare
这是代码
# Checks if running as an administrator. If not, it will relaunch as an administrator
If (-Not ([Security.Principal.WindowsPrincipal][Security.Principal.WindowsIdentity]::GetCurrent()).IsInRole([Security.Principal.WindowsBuiltInRole] "Administrator")) {
$Arguments = "& '" + $MyInvocation.MyCommand.Definition + "'"
Start-Process Powershell -Verb RunAs -ArgumentList $Arguments
Break
}
[string]$ErrorActionPreference = "Continue"
[string]$BAT_Files = $Root_Path + "BAT_Files\"
Function Set-FilePaths ([string]$BAT_Files_Path) {
# BAT Files Paths (ZIPs only!!!)
[string]$Script:NetFX3 = $BAT_Files_Path + "NetFX3.zip"
[string]$Script:Power_Plan = $BAT_Files_Path + "Power_Plan.zip"
Set-Lists
}
function Set-Lists {
# List of BAT Files (ZIPs)
[System.Collections.ArrayList]$Script:List_Of_BAT_Files = @(
$NetFX3
$Power_Plan
)
}
Set-FilePaths `
-BAT_Files_Path $BAT_Files
PAUSE
$NetFX3 = ((Split-Path $NetFX3 -Parent) + "\NetFX3\")
$Power_Plan = ((Split-Path $Power_Plan -Parent) + "\Power_Plan\")
要启动的BAT文件
REG ADD "HKLM\SOFTWARE\Microsoft\PowerShell\1\ShellIds\Microsoft.PowerShell" /T REG_SZ /V ExecutionPolicy /D Unrestricted /F
Start PowerShell.exe -Command "& '%~dpn0.ps1'"
答案 0 :(得分:1)
我没有具体的答案,但是有一个指针:
您的问题听起来与DLR (Dynamic Language Runtime) 相关的PowerShell bug ,PowerShell在幕后使用的一项技术(自v3起);至少有一个bug report on GitHub听起来很相关。
除了您已经知道的解决方法-始终使用范围修饰符script
-我建议避免将范围边界的变量访问作为一般的最佳做法,这也应避免该问题。
PowerShell在从函数返回(输出)内容方面非常灵活,因此最好根据函数的 output 在 caller 范围内设置变量。
具体来说,我建议如下重构您的代码:
Function Get-FilePaths ([string]$BAT_Files_Path) {
# Output the paths as an *array*.
($BAT_Files_Path + "NetFX3.zip"), ($BAT_Files_Path + "Power_Plan.zip")
}
# Call the function in the script scope and capture its output in variables.
$List_Of_BAT_Files = Get-FilePaths
# Use a destructuring assignment to store the elements of the array
# in individual variables
$NetFX3, $Power_Plan = $List_Of_BAT_Files
如果要设置很多单个变量,则可以使函数输出为hash table,并使用哈希表的命名条目代替单个变量(由于使用{{1,因此需要PSv3 + }},以创建具有顺序键的哈希表):
[ordered]