【问题标题】:How to create a dynamic variable in Powershell, sucha as date/time etc如何在 Powershell 中创建动态变量,例如日期/时间等
【发布时间】:2013-01-07 02:00:05
【问题描述】:

您好,我不确定我的措辞是否正确,但每当我将数据写入日志时,我都需要一个包含 当前 日期/时间的变量;如果不每次都初始化,我怎么能做到这一点。目前每次我需要更新时,我都会同时使用这两个语句。还有其他方法吗?

$DateTime = get-date  | select datetime
Add-Content $LogFile -Value "$DateTime.DateTime: XXXXX"

如果对我的问题有任何疑问或澄清,请告诉我。

【问题讨论】:

    标签: variables powershell dynamic


    【解决方案1】:

    此脚本在 Powershell 中生成真正的动态变量(感谢Lee Holmes 和他的Windows PowerShell Cookbook The Complete Guide to Scripting Microsoft's Command Shell, 3rd Edition

    ##############################################################################
    ##
    ## New-DynamicVariable
    ##
    ## From Windows PowerShell Cookbook (O'Reilly)
    ## by Lee Holmes (http://www.leeholmes.com/guide)
    ##
    ##############################################################################
    
    <#
    
    .SYNOPSIS
    
    Creates a variable that supports scripted actions for its getter and setter
    
    .EXAMPLE
    
    PS > .\New-DynamicVariable GLOBAL:WindowTitle `
         -Getter { $host.UI.RawUI.WindowTitle } `
         -Setter { $host.UI.RawUI.WindowTitle = $args[0] }
    
    PS > $windowTitle
    Administrator: C:\Windows\System32\WindowsPowerShell\v1.0\powershell.exe
    PS > $windowTitle = "Test"
    PS > $windowTitle
    Test
    
    #>
    
    param(
        ## The name for the dynamic variable
        [Parameter(Mandatory = $true)]
        $Name,
    
        ## The scriptblock to invoke when getting the value of the variable
        [Parameter(Mandatory = $true)]
        [ScriptBlock] $Getter,
    
        ## The scriptblock to invoke when setting the value of the variable
        [ScriptBlock] $Setter
    )
    
    Set-StrictMode -Version 3
    
    Add-Type @"
    using System;
    using System.Collections.ObjectModel;
    using System.Management.Automation;
    
    namespace Lee.Holmes
    {
        public class DynamicVariable : PSVariable
        {
            public DynamicVariable(
                string name,
                ScriptBlock scriptGetter,
                ScriptBlock scriptSetter)
                    : base(name, null, ScopedItemOptions.AllScope)
            {
                getter = scriptGetter;
                setter = scriptSetter;
            }
            private ScriptBlock getter;
            private ScriptBlock setter;
    
            public override object Value
            {
                get
                {
                    if(getter != null)
                    {
                        Collection<PSObject> results = getter.Invoke();
                        if(results.Count == 1)
                        {
                            return results[0];
                        }
                        else
                        {
                            PSObject[] returnResults =
                                new PSObject[results.Count];
                            results.CopyTo(returnResults, 0);
                            return returnResults;
                        }
                    }
                    else { return null; }
                }
                set
                {
                    if(setter != null) { setter.Invoke(value); }
                }
            }
        }
    }
    "@
    
    ## If we've already defined the variable, remove it.
    if(Test-Path variable:\$name)
    {
        Remove-Item variable:\$name -Force
    }
    
    ## Set the new variable, along with its getter and setter.
    $executioncontext.SessionState.PSVariable.Set(
        (New-Object Lee.Holmes.DynamicVariable $name,$getter,$setter))
    

    有一个Set-StrictMode -Version 3,但如果您可以按照Here 的说明在您的 powershell V2.0 会话中加载框架 4.0,则可以将其设置为 -Version 2。

    OP 的用途是:

     New-DynamicVariable -Name GLOBAL:now -Getter { (get-date).datetime }
    

    这是 Lee Holmes 对我在其他答案中使用的方法的评估(很明显真正的缺陷是什么):

    Note
    There are innovative solutions on the Internet that use PowerShell's debugging facilities to create a breakpoint that changes a variable's value whenever you attempt to read from it. While unique, this solution causes PowerShell to think that any scripts that rely on the variable are in debugging mode. This, unfortunately, prevents PowerShell from enabling some important performance optimizations in those scripts.
    

    【讨论】:

      【解决方案2】:

      为什么不使用:

      Add-Content $LogFile -Value "$((Get-Date).DateTime): XXXXX"
      

      每次都会获取当前的日期时间。请注意,它在 $( ) 内部,这使得 powershell 在将其插入字符串之前运行表达式(获取日期时间)。

      【讨论】:

      • 为什么今天有人反对我? :S 这是一个很好的答案! :P
      • 我没有投反对票,但我猜是因为你解决了问题,但没有回答@CB 的问题 .'s answer确实如此。
      • 问题是“有没有其他方法可以做到这一点?”,我回答了。我没有回答标题,但我在他的帖子中回答了这个问题。实际上,字符串中的子表达式可以被认为是变量,只需指定更长的名称(表达式,可以多次重复使用而无需任何修改,就像变量一样),所以你甚至可以说我回答了标题。 :) 不过不用担心,它解决了@Darktux 的问题。
      【解决方案3】:

      将你的两个命令包装在函数中,这样你就只有一个调用了?

      function add-log{
      (param $txt)
      $DateTime = get-date  | select -expand datetime
      Add-Content $LogFile -Value "$DateTime: $txt"
      }
      

      【讨论】:

        【解决方案4】:

        除了这些其他方式(坦率地说,我可能会改用——断点方法除外),您可以创建一个带有 ScriptProperty 的自定义对象,您可以为其提供实现:

        $obj = new-object pscustomobject
        $obj | Add-Member ScriptProperty Now -Value { Get-Date }
        $obj.now
        

        【讨论】:

        • 我添加了一个新答案 [不是为了荣耀 ;) ] IMO 绝对正确 ;)
        • @C.B.是的,我更喜欢这种方法。
        【解决方案5】:

        使用PsBreakPoint:

        $act= @'
        $global:now = (get-date).datetime
        '@
        $global:sb = [scriptblock]::Create($act)
        $now = Set-PSBreakpoint -Variable now -Mode Read -Action $global:sb
        

        调用$now 返回当前更新的日期时间值

        一个班轮:

        $now = Set-PSBreakpoint -Variable now -Mode Read -Action { $global:now = (get-date).datetime }
        

        【讨论】:

        • @Graimer 只需将其放在您的个人资料中,无论您身在何处都可以使用 $now,这里没有复杂性,我认为这应该是一个内置的 ps var。
        • 对于配置文件脚本,我同意。 :) 然而,问题是针对脚本(我猜),为此,无论是函数还是 $(..) 都更好,但这只是我的意见。
        • 好吧,除非您调试完脚本并执行get-psbreakpoint | remove-psbreakpoint。此时 $now 返回一个比错误更糟糕的固定时间值。
        • 只是添加另一个意见:如果您知道我们有这样的变量,我认为运行 get-psbreakpoint | remove-psbreakpoint 是不明智的,因为它很容易通过 where 对象避免。可能是代码字符太多?
        • 这只是你很容易忘记的东西。当我调试脚本并到处设置断点时,我通常会在完成后将它们全部清除。可以肯定的是,这是一种有趣且聪明的方法。我只是觉得它有点脆。如果我从某人那里得到一个在我的会话中设置断点的脚本,我会觉得这有点烦人。
        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 2014-08-13
        • 2014-10-04
        • 2014-02-24
        • 2017-07-30
        • 2011-02-23
        • 2016-04-19
        • 1970-01-01
        相关资源
        最近更新 更多