Expand string without Invoke-Expression

前端 未结 3 1265
忘了有多久
忘了有多久 2021-01-14 00:20

Imagine the following code:

# Script Start
$WelcomeMessage = \"Hello $UserName, today is $($Date.DayOfWeek)\"

..
..
# 100 lines of other functions and what          


        
相关标签:
3条回答
  • 2021-01-14 00:36

    Have you considered using a lambda expression; i.e. instead of defining the variable as a string value define it as a function, then invoke that function passing the relevant parameters at runtime.

    $WelcomeMessage = {param($UserName,$Date);"Hello $UserName, today is $($Date.DayOfWeek) $([void](remove-item c:\test\test.txt))"}
    
    #...
    # 100 lines of other functions and what not...
    #...
    
    "testfile" >> c:\test\test.txt #ensure we have a test file to be deleted
    
    function Get-UserNameFromSomewhereFancy(){return "myUsername";}
    function Get-DateFromSomewhereFancy(){return (get-date);}
    
    function Greet-User
    {
        $Username = Get-UserNameFromSomewhereFancy
        $Date = Get-DateFromSomewhereFancy
    
        $WelcomeMessage.invoke($username,$date)
    }
    
    cls
    Greet-User
    

    Update

    If you only wish to allow variable replacement the below code would do the trick; but this fails to do more advanced functions (e.g. .DayOfWeek)

    $WelcomeMessage = 'Hello $Username, today is $($Date.DayOfWeek) $([void](remove-item c:\test\test.txt))'
    #...
    # 100 lines of other functions and what not...
    #...
    
    "testfile" >> c:\test\test.txt #ensure we have a test file to be deleted
    
    function Get-UserNameFromSomewhereFancy(){return "myUsername";}
    function Get-DateFromSomewhereFancy(){return (get-date);}
    function Resolve-WelcomeMessage(){
        write-output {param($UserName,$Date);"$WelcomeMessage";}
    }
    function Greet-User
    {
        $Username = Get-UserNameFromSomewhereFancy
        $Date = Get-DateFromSomewhereFancy
        $temp = $WelcomeMessage 
        get-variable | ?{@('$','?','^') -notcontains $_.Name} | sort name -Descending | %{
            $temp  = $temp -replace ("\`${0}" -f $_.name),$_.value
        }
        $temp 
    }
    
    cls
    Greet-User
    

    Update

    To avoid code injection this makes use of -whatif; that will only help where the injected code supports the whatif functionality, but hopefully better than nothing...

    Also the code now doesn't require parameters to be declared; but just takes those variables which are available at the time of execution.

    $WelcomeMessage = {"Hello $Username, today is $($Date.DayOfWeek) $([void](remove-item c:\test\test.txt))"}
    
    #...
    # 100 lines of other functions and what not...
    #...
    
    function Get-UserNameFromSomewhereFancy(){return "myUsername";}
    function Get-DateFromSomewhereFancy(){return (get-date);}
    function Resolve-WelcomeMessage(){
        write-output {param($UserName,$Date);"$WelcomeMessage";}
    }
    
    "testfile" >> c:\test\test.txt #ensure we have a test file to be deleted
    
    function Greet-User {
        [cmdletbinding(SupportsShouldProcess=$True)]
        param()
        begin {$original = $WhatIfPreference; $WhatIfPreference = $true;}
        process {
            $Username = Get-UserNameFromSomewhereFancy
            $Date = Get-DateFromSomewhereFancy
            & $WelcomeMessage 
        }
        end {$WhatIfPreference = $original;}
    }
    
    cls
    Greet-User
    
    0 讨论(0)
  • 2021-01-14 00:44

    The canonical way to delay evaluation of expressions/variables in strings is to define them as single-quoted strings and use $ExecutionContext.InvokeCommand.ExpandString() later on.

    Demonstration:

    PS C:\> $s = '$env:COMPUTERNAME'
    PS C:\> $s
    $env:COMPUTERNAME
    PS C:\> $ExecutionContext.InvokeCommand.ExpandString($s)
    FOO

    Applied to your sample code:

    $WelcomeMessage = 'Hello $UserName, today is $($Date.DayOfWeek)'
    
    ...
    ...
    ...
    
    function Greet-User {
      $Username = Get-UserNameFromSomewhereFancy
      $Date = Get-DateFromSomewhereFancy
    
      $ExecutionContext.InvokeCommand.ExpandString($WelcomeMessage)
    }
    
    0 讨论(0)
  • 2021-01-14 00:45

    Embedding variables into strings is not the only way to create dynamic text, the way I would do it is like this:

    $WelcomeMessage = 'Hello {0}, today is {1}'
    
    # 100 lines of other functions and what not...
    
    function Greet-User
    {
        $Username = Get-UserNameFromSomewhereFancy
        $Date = Get-DateFromSomewhereFancy
    
        $WelcomeMessage -f $Username, $Date
    }
    
    0 讨论(0)
提交回复
热议问题