Лучшая практика в powershell Try / Catch / Finally scripting?

#powershell

#powershell

Вопрос:

Интересно, возможно ли удалить все переменные, используемые в текущем сеансе скрипта?

 Try {
    Write-Host "Scripting start...."
}
Catch {
    Write-Warning -Message "[PROCESS] Something wrong happened"
    Write-Warning -Message $Error[0].Exception.Message
}
Finally {
    Remove-Variable *
    [System.GC]::Collect() 
}
  

Если нет, что я могу сделать в Finally блоке?

Ответ №1:

Лучше всего называть вашу пользовательскую переменную некоторой энтропией, чтобы их было легко найти и удалить. Удаление ‘*’ удаляет все, независимо от того, когда / как это было создано, включая все переменные PS по умолчанию.

Не делайте этого.

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

Итак, в моем случае я бы использовал, скажем…

 $panVariableName 
  

… затем

 Remove-Variable -Name 'pan*' -Force
  

Или, если вы не хотите делать это таким образом. При запуске сеанса сделайте это…

 $AutomaticVariables = Get-Variable
  

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

Итак, в моем профиле модуля это находится вверху…

 $AutomaticVariables = Get-Variable
  

Затем, когда я буду готов, вызывается эта функция.

 Function Clear-ResourceEnvironment
{
    [CmdletBinding(SupportsShouldProcess)]
    [Alias('cre')]
    
    Param
    (
        [switch]$AdminCredStore
    )
    
 
    [System.GC]::Collect()
    [GC]::Collect()
    [GC]::WaitForPendingFinalizers()
    
    Get-PSSession | 
    Remove-PSSession -ErrorAction SilentlyContinue
    
    If ($AdminCredStore)
    {Remove-Item -Path "$env:USERPROFILEDocumentsAdminCredSet.xml" -Force}
    Else 
    {
        Write-Warning -Message "`n`t`tYou decided not to delete the custom Admin credential store. 
        This store is only valid for this host and user $env:USERNAME"
    } 
    
    Write-Warning -Message "`n`t`tRemoving the displayed session specific variable ojects"
    
    Compare-Object -ReferenceObject (Get-Variable) -DifferenceObject $AutomaticVariables -Property Name -PassThru | 
    Where -Property Name -ne 'AutomaticVariables' | 
    Remove-Variable -Verbose -Force -Scope 'global' -ErrorAction SilentlyContinue
    Remove-Variable -Name AdminCredStore -Verbose -Force
}
  

Ответ №2:

Я полагаю, вы можете использовать:

 Clear-Variable * -Scope Global
  

или

 Remove-Variable * -Scope Global
  

В качестве альтернативы, решит ли вашу проблему определение области действия процесса? Вы можете создать scriptblock и вызвать его с помощью «оператора вызова» ( amp; ). Это позволило бы запустить процесс в ограниченной среде, отдельной от глобальной. Это выглядело бы примерно так:

 $scriptBlock = { 
    Try {
        Write-Host "Scripting start...."
    }
    Catch {
        Write-Warning -Message "[PROCESS] Something wrong happened"
        Write-Warning -Message $Error[0].Exception.Message
    }
    Finally {
        [System.GC]::Collect() 
    }
}

amp;$scriptBlock
  

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

Комментарии:

1. Привет @Andrew, спасибо за быстрый ответ. Итак, если я запускаю скрипт локально, будет ли применима оболочка $ ScriptBlock?

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

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

4. Потрясающе, так что, если это есть в этом try / catch, тогда вы можете удалить их из оператора вызова с ограниченной областью действия (amp;). В противном случае другие параметры должны работать, если они вызваны в конце.