PowerShell $ PROFILE, переменные и NoteProperty / Add-Member - PullRequest
1 голос
/ 13 февраля 2020

$profile вызывает у меня некоторые головные боли. $Profile.GetType() разрешается в String, что нормально, но имеет значения NoteProperty:

$profile | Get-Member -Type NoteProperty

AllUsersAllHosts, AllUsersCurrentHost, CurrentUserAllHosts, CurrentUserCurrentHost

Когда я набираю $profile, возвращается NoteProperty CurrentUserCurrentHost. Это нормально, но мне нужно изменить это значение - это сложно, но мой корпоративный VPN использует сетевой профиль, и когда я в сети, он пытается сослаться на это местоположение для моего $profile, что означает, что каждый запуск консоли занимает 9 секунд (ужасно медленно ). Я могу получить это значение до 1 se c, если профиль загружен локально, но это означает изменение этих значений. Чтобы сделать это, я поместил следующее в AllUsersAllHosts profile.ps1

$profile = C:\Users\($env:Username)\Documents\WindowsPowerShell\Microsoft.PowerShell_profile.ps1"

Это нормально, но, делая это, я обнаружил, что все значения NoteProperty удалены! Поэтому я попытался:

$profile.CurrentUserCurrentHost = C:\Users\($env:Username)\Documents\WindowsPowerShell\Microsoft.PowerShell_profile.ps1"

Но это не удалось, так как значение root $ Profile продолжает указывать на сетевой профиль, а запуск консоли снова через 9 секунд!

Затем я тоже заметил следующую странность:

$x = [string]$profile
$x -eq $profile

Вот основные вопросы:

• Почему $ x возвращает True, хотя у $ x нет ни одного из NoteProperty значений в $profile (поскольку объекты определенно не совпадают!)?

• Как мне контролировать значение root $profile, не разрушая значения NoteProperty и

• Как я могу обновить .CurrentUserAllHosts и .CurrentUserCurrentHost таким образом, чтобы значение root также обновлялось соответствующим образом? т.е. даже если я сделаю следующее, значение root $profile останется неизменным (все еще указывает на очень медленное расположение профиля сети):

Add-Member -InputObject $PROFILE -NotePropertyName "AllUsersAllHosts" -NotePropertyValue "C:\Windows\System32\WindowsPowerShell\v1.0\profile.ps1"
Add-Member -InputObject $PROFILE -NotePropertyName "AllUsersCurrentHost" -NotePropertyValue "C:\Windows\System32\WindowsPowerShell\v1.0\Microsoft.PowerShell_profile.ps1"
Add-Member -InputObject $PROFILE -NotePropertyName "CurrentUserAllHosts" -NotePropertyValue "C:\Users\$($env:Username)\Documents\WindowsPowerShell\profile.ps1"
Add-Member -InputObject $PROFILE -NotePropertyName "CurrentUserCurrentHost" -NotePropertyValue "C:\Users\$($env:Username)\Documents\WindowsPowerShell\Microsoft.PowerShell_profile.ps1"

Ответы [ 2 ]

1 голос
/ 13 февраля 2020

Хотя технически возможно копировать элементы NoteProperty из одного строкового экземпляра в другой (см. Ниже), к сожалению, это вам не поможет:

PowerShell предоставляет переменную $PROFILE для преимущество пользователя:

  • Он не использует значения этой переменной внутренне для определения местоположения профиля при загрузке профиля,
  • эти местоположения профиля не конфигурируемые .

Вы должны рассматривать $PROFILE как переменную только для чтения , даже если она технически может быть изменена .

* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *}}}}} * * * * * * * * * 10 создайте выделенный файл ярлыков (*.lnk) для запуска сеансов PowerShell, определяемый целевой командой, например:

powershell -noprofile -noexit -c ". c:\CustomProfileDir\profile.ps1"

Чтобы использовать PowerShell [Core] 6+, подставьте pwsh для powershell. * 10 39 *


Копирование элементов NoteProperty между объектами:

Примечание:

  • Как указано, это не решит вашу проблему, но он показывает, как члены NoteProperty можно копировать из одного объекта в другой, даже между строками, которые имеют разные значения.

  • В частности, с [string] экземплярами, используя -PassThru и присваивая обратно входная переменная ($obj = $obj | Add-Member -PassThru ...) требуется для сохранения членов NoteProperty; для других типов достаточно $obj | Add-Member ....

# Assign the new string value to a new (temporary) variable.
$newProfile = '/path/to/my.ps1'

# Copy the NoteProperty members from the original, decorated string
# to the new variable's string instance.
$PROFILE.psobject.properties | where MemberType -eq 'NoteProperty' | foreach { 
  $newProfile = $newProfile |
    Add-Member -PassThru -NotePropertyName $_.Name -NotePropertyValue $_.Value  
}

# You can now assign the new variable to the old one,
# but note that *with $PROFILE that won't help*.
# $PROFILE SHOULD BE TREATED AS READ-ONLY.
$PROFILE = $newProfile 
0 голосов
/ 14 февраля 2020

Как указал @ mklement0, я не могу обойти функциональность $ profile, но могу обмануть. Без описанного ниже все оболочки и сценарии запускаются с 6,5 до 9 минут c, когда я удаленно подключаюсь к своей корпоративной VPN (часть этого, около 3 секунд - это мои $profile функции и c). С учетом приведенного ниже все консоли и сценарии запускаются за 1 секунду (и это включает в себя мои $profile функции с примерно 1000 строками кода). Размещение этого решения здесь в случае помощи другим.

Выполнение кода внизу этого ответа приводит к тому, что в мой $Profile.AllUsersAllHosts вставляется следующее, которое теперь всегда будет ссылаться на профиль по умолчанию C: \ location (и правильно для каждого типа хоста - console, ISE, VSCode et c).

Set-Location C:\Users\$($env:Username)

# Prevent loading profile from network share
if ($Profile.CurrentUserCurrentHost -ne "C:\Users\$($env:Username)\Documents\WindowsPowerShell\$(($Profile).split(`"\`")[-1])") {
    $Profile = "C:\Users\$($env:Username)\Documents\WindowsPowerShell\$(($Profile).split(`"\`")[-1])"
    if (Test-Path "$Profile") { . $Profile }
}

Все, что мне тогда нужно сделать, это удалить все профили на сетевом ресурсе, и теперь я получаю 1 время второй загрузки, независимо от того, подключен ли удаленно к VPN или нет, открываю ли я консоль или сценарий и т. д. c.

Write-Host ""
Write-Host "Do you want to update `$Profile.AllUsersAllHosts to always redirect to C:\Users\$($env:Username) ?"
Write-Host "This can significantly speed up PowerShell load times when working with a network share over a VPN."
Write-Host "Note that this is just a bypass to always use the *default* profile location on C:\."
Write-Host "   `$Profile.AllUsersAllHosts = C:\Windows\System32\WindowsPowerShell\v1.0\profile.ps1"
Write-Host "   `$Profile.CurrentHostCurrentUser = C:\Users\$($env:Username)\Documents\WindowsPowerShell\$(($Profile).split("\"))[-1]_profile.ps1"
Write-Host ""

$ProfileAdmin = "C:\Windows\System32\WindowsPowerShell\v1.0\profile.ps1"
# Use  (($Profile).split("\"))[-1]  to capture correct prefix PowerShell, VSCode. $ShellId does not work for VSCode etc
$ProfileUser = "C:\Users\$($env:Username)\Documents\WindowsPowerShell\$(($Profile).split('\')[-1])"
$ProfileUserText = '"C:\Users\$($env:Username)\Documents\WindowsPowerShell\$(($Profile).split(`"\`")[-1])"'

Write-Host "Press any key to use `$Profile.AllUsersAllHosts to stop using a profile from a network share"
pause
# - Create $Profile.AllUsersAllHosts
# - Set-Location C:\Users\$($env:Username)   (override Admin defaulting into system32)
# - If the system decides that it will use C:\ have to check that so that we do not double-load $Profile!
# - If that condition is ok, set $Profile = "C:\Users\$($env:Username)\Documents\WindowsPowerShell\$($ShellId)_profile.ps1"
# - Then just dotsource $Profile as it's set to the C:\ drive as required.
if (!(Test-Path $(Split-Path $ProfileAdmin))) { mkdir $(Split-Path $ProfileAdmin) -Force }
if (!(Test-Path $(Split-Path $ProfileUser))) { mkdir $(Split-Path $ProfileUser) -Force }
Write-Host "`nCreating backup of existing profile ..."
If (Test-Path $ProfileAdmin) { Copy-Item -Path "$($ProfileAdmin)" -Destination "$($ProfileAdmin)_$(Get-Date -format "yyyy-MM-dd__HH-mm-ss").txt" }
Set-Content -Path $ProfileAdmin -Value "Set-Location C:\Users\`$(`$env:Username)"
Add-Content -Path $ProfileAdmin -Value ""
Add-Content -Path $ProfileAdmin -Value "# Prevent loading profile from network share"
Add-Content -Path $ProfileAdmin -Value "if (`$Profile.CurrentUserCurrentHost -ne $ProfileUserText) {"
Add-Content -Path $ProfileAdmin -Value "    `$Profile = $ProfileUserText"
Add-Content -Path $ProfileAdmin -Value "    if (Test-Path `"`$Profile`") { . `$Profile }"
Add-Content -Path $ProfileAdmin -Value "}"
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...