Режим администратора и не-администратора - невозможно перезаписать переменную, поскольку переменная была оптимизирована - PullRequest
0 голосов
/ 09 октября 2018

Сегодня во время некоторых испытаний я натолкнулся на неожиданную проблему, и я не понимаю, почему это происходит.Ниже приведен код, который я использую для дублирования проблемы.Это только очень небольшая часть более крупного проекта.

На Windows 10 Build 1709 проводится тестирование, если это помогает

И файл PS1, и файл BAT называются одинаково.

Способы возникновения ошибок

  • Запуск файла PS1 через Right-Click - Run with PowerShell приведет к ошибке
  • Открытие PowerShell ISE in Non-Admin Mode, затем открытие / запуск скрипта вызовет ошибку
  • Запуск BAT-файла как Admin или Non-Admin вызовет ошибку

Способы избежать ошибок

  • Открытие PowerShell ISE в режиме Admin , затем открытие / запуск скрипта не вызывает ошибку
  • Добавление Script: перед переменными в последних 2 строках кода не вызывает ошибку независимо от того, как выполняется скрипт
  • Используя VSCode, он будет работать, как показано ниже.Запустив его во встроенном терминале, он увидит, что он не работает как Admin, он запустит PowerShell.exe вне VSCode и будет работать без проблем

-

ПочемуУ меня Script: перед переменными в функциях?Это был единственный способ получить переменные, установленные в функциях, для использования вне функций.Другие 25 или около того переменных, не перечисленных в этом посте, не имеют проблем, однако они не модифицируются, как эти две после их установки.

Вопросы

  • Почему, если ISE работает в режиме Admin, он будет работать?
  • Почему он не будет работать, если он перезапустится с правами администратора?
  • Почему VSCode все равнои это работает независимо?

Что-то не имеет смысла, и я не могу точно определить это.

Вот ошибки

Невозможно перезаписать переменную NetFX3, поскольку переменная была оптимизирована.Попробуйте использовать командлет New-Variable или Set-Variable (без псевдонимов) или введите в точку команду, которую вы используете для установки переменной.В 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 (без псевдонимов) или введите в точку команду, которую вы используете для установки переменной.В 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'"

1 Ответ

0 голосов
/ 10 октября 2018

У меня нет конкретного ответа, но указатель:

Ваша проблема звучит как PowerShell ошибка , относящаяся к DLR (динамическая языковая среда выполнения) , технология PowerShell используется за кулисами (начиная с v3);есть по крайней мере один открытый отчет об ошибке на GitHub , который звучит как связанный.


Помимо обходного пути, о котором вы уже знаете - постоянное использование модификатора области script - Я предлагаюкак правило, избегайте доступа к переменным через границы области действия , что также должно избежать проблемы.

PowerShell очень гибок в том, что он может возвращать (выводить) из функции, поэтому лучше устанавливать переменныев области действия вызывающего на основе вывода функции .

В частности, я предлагаю рефакторинг вашего кода следующим образом:

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

Если нужно установить множество отдельных переменных, вы можете вместо функции сделать вывод хеш-таблицы и использовать именованные записи хеш-таблицы вместо отдельных переменных (требуется PSv3 +, из-за использования [ordered] для создания хеш-таблицы с упорядоченными ключами):

Function Get-FilePaths ([string]$BAT_Files_Path) {
  # Output the paths as a *hash table*, using its
  # entries for named access instead of individual variables.
  $outHash = [ordered] @{
    NetFX3 = $BAT_Files_Path + "NetFX3.zip"
    Power_Plan = $BAT_Files_Path +  "Power_Plan.zip"
  }
  # Add a 'List' entry that contains all values added above as an array.
  # Note the need to use @(...) to force creation of a new array from the
  # hash table's value collection.
  $outHash.List = @($outHash.Values)
  # Output the hash table.
  $outHash
}

# Call the function in the script scope and capture its output in 
# a single variable that receives the hash table.
$hash = Get-FilePaths

# Now you can access the invididual values by name - e.g., $hash.NetFX3 -
# or use $hash.List to get all values.
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...