首页 > 解决方案 > Powershell - 变量问题

问题描述

我编写了一个脚本,该脚本将从 .properties 文件(基本上是一个配置文件)中提取数据。属性文件中的一些数据具有环境数据(即 %UserProfile%),因此我通过一个函数(Resolve–EnvVariable)运行它,该函数将用实际值替换环境变量。替换工作完美,但不知何故,数据似乎被改变了。当我尝试使用通过函数运行的值时,它们不再起作用(见下面的结果)。

这是 c:\work\test.properties 的文件内容

types="*.txt"
in="%UserProfile%\Downloads"

这是我的 PowerShell 脚本

Clear-Host
#Read the properties file and replace the parameters when specified
if (Test-Path C:\work\test.properties) {
    $propertiesFile = Get-Content C:\work\test.properties
    Write-Host "Parameters will be substituded from properties file" -ForegroundColor Yellow
    foreach ($line in $propertiesFile) {
        Write-Host ("from Properties file $line")
        $propSwitch = $line.Split("=")[0]
        $propValue = Resolve–EnvVariable($line.Split("=")[1])
        switch ($propSwitch) {
            "types" { $types = $propValue }
            "in" { $in = $propValue }
        }
    }
}
write-host ("After running through function `n in=" + $in + "<-   types=" + $types + "<-")

# This function resolves environment variables
Function Resolve–EnvVariable {
    [cmdletbinding()]
    Param(
        [Parameter(Position = 0, ValueFromPipeline = $True, Mandatory = $True,
            HelpMessage = "Enter string with env variable i.e. %APPDATA%")]
        [ValidateNotNullOrEmpty()]
        [string]$String
    )

    Begin {
        Write-Verbose "Starting $($myinvocation.mycommand)"
    } #Begin

    Process {  
        #if string contains a % then process it
        if ($string -match "%\S+%") {
            Write-Verbose "Resolving environmental variables in $String"
            #split string into an array of values
            $values = $string.split("%") | Where-Object { $_ }
            foreach ($text in $values) {
                #find the corresponding value in ENV:
                Write-Verbose "Looking for $text"
                [string]$replace = (Get-Item env:$text -erroraction "SilentlyContinue").Value
                if ($replace) {
                    #if found append it to the new string
                    Write-Verbose "Found $replace"
                    $newstring += $replace
                }
                else {
                    #otherwise append the original text
                    $newstring += $text
                }

            } #foreach value

            Write-Verbose "Writing revised string to the pipeline"
            #write the string back to the pipeline
            Write-Output $NewString
        } #if
        else {
            #skip the string and write it back to the pipeline
            Write-Output $String
        }
    } #Process

    End {
        Write-Verbose "Ending $($myinvocation.mycommand)"
    } #End
} #end Resolve-EnvVariable


# Hardcoded values work
$test1 = Get-ChildItem -Path "C:\Users\Paul\Downloads" -Recurse -Include "*.txt" 

# Values pulled and updated through function do not work
$test2 = Get-ChildItem -Path $in -Recurse -Include $types 

# If I manually assign the values, it works
$in = "C:\Users\Paul\Downloads" 
$types = "*.txt"
$test3 = Get-ChildItem -Path $in -Recurse -Include $types 

foreach ($test in $test1) { write-host "test1 $test" }
foreach ($test in $test2) { write-host "test2 $test" }
foreach ($test in $test3) { write-host "test3 $test" }

结果

Parameters will be substituded from properties file
from Properties file types="*.txt"
from Properties file in="%UserProfile%\Downloads"
After running through function 
 in="C:\Users\Paul\Downloads"<-   types="*.txt"<-
test1 C:\Users\Paul\Downloads\Test\testPaul.txt
test1 C:\Users\Paul\Downloads\Test2\File1.txt
test3 C:\Users\Paul\Downloads\Test\testPaul.txt
test3 C:\Users\Paul\Downloads\Test2\File1.txt

标签: powershellenvironment-variables

解决方案


两种选择:

1.使用Environment.ExpandEnvironmentVariables()

如果您切换到非限定字符串值并转义您的\,它就像将文件管道传输到 一样简单ConvertFrom-StringData,此时您可以使用 扩展变量值Environment.ExpandEnvironmentVariables()

属性文件:

types=*.txt
in=%UserProfile%\\Downloads

脚本:

# Convert file to hashtable
$properties = Get-Content file.properties -Raw |ConvertFrom-StringData

# Copy value to new hashtable, but expand env vars first
$expanded = @{}
foreach($entry in $properties.GetEnumerator()){
    $expanded[$entry.Key] = [Environment]::ExpandEnvironmentVariables($entry.Value)
}

应该给你想要的值:

PS C:\> $expanded

Name                           Value
----                           -----
in                             C:\Users\username\Downloads
types                          *.txt

2. 为您的属性使用和点源 PowerShell 脚本

这是直接从原始 Exchange Server 模块的页面中提取出来的 - 将所有配置变量放在单独的脚本中,这些脚本在初始化新会话时又是点源代码:

属性文件:

$types = "*.txt"
$in = Join-Path $env:USERPROFILE Downloads

脚本:

# dot source the variables
. (Join-Path $PSScriptRoot properties.ps1)

# do the actual work
Get-ChildItem $in -Include $types

推荐阅读