gpt4 book ai didi

powershell - 无法从函数内部修改脚本范围的变量

转载 作者:行者123 更新时间:2023-12-03 00:28:45 25 4
gpt4 key购买 nike

我目前正在制作一个脚本,该脚本应该连接到 42 个不同的本地服务器,并从事件目录中获取特定组的用户 (fjärrskrivbordsanvändare(瑞典语中的远程桌面用户:D))。从服务器获取所有用户后,它必须将用户导出到我桌面上的文件

csv 文件必须如下所示:

Company;Users
LawyerSweden;Mike
LawyerSweden;Jennifer
Stockholm Candymakers;Pedro
(Examples)
etc.

这是目前的代码:
cls

$MolnGroup = 'fjärrskrivbordsanvändare'
$ActiveDirectory = 'activedirectory'
$script:CloudArray
Set-Variable -Name OutputAnvandare -Value ($null) -Scope Script
Set-Variable -Name OutputDomain -Value ($null) -Scope Script

function ReadInfo {

Write-Host("A")

Get-Variable -Exclude PWD,*Preference | Remove-Variable -EA 0

if (Test-Path "C:\file\frickin\path.txt") {

Write-Host("File found")

}else {

Write-Host("Error: File not found, filepath might be invalid.")
Exit
}


$filename = "C:\File\Freakin'\path\super.txt"
$Headers = "IPAddress", "Username", "Password", "Cloud"

$Importedcsv = Import-csv $filename -Delimiter ";" -Header $Headers

$PasswordsArray += @($Importedcsv.password)
$AddressArray = @($Importedcsv | ForEach-Object { $_.IPAddress } )
$UsernamesArray += @($Importedcsv.username)
$CloudArray += @($Importedcsv.cloud)

GetData
}

function GetData([int]$p) {

Write-Host("B")

for ($row = 1; $row -le $UsernamesArray.Length; $row++)
{
# (If the customer has cloud-service on server, proceed)
if($CloudArray[$row] -eq 1)
{

# Code below uses the information read in from a file to connect pc to server(s)

$secstr = New-Object -TypeName System.Security.SecureString
$PasswordsArray[$row].ToCharArray() | ForEach-Object {$secstr.AppendChar($_)}
$cred = new-object -typename System.Management.Automation.PSCredential -argumentlist $UsernamesArray[$row], $secstr

# Runs command on server

$OutputAnvandare = Invoke-Command -computername $AddressArray[$row] -credential $cred -ScriptBlock {

Import-Module Activedirectory

foreach ($Anvandare in (Get-ADGroupMember fjärrskrivbordsanvändare))
{

$Anvandare.Name
}
}

$OutputDomain = Invoke-Command -computername $AddressArray[$row] -credential $cred -ScriptBlock {

Import-Module Activedirectory

foreach ($Anvandare in (Get-ADGroupMember fjärrskrivbordsanvändare))
{

gc env:UserDomain
}
}

$OutputDomain + $OutputAnvandare
}
}
}


function Export {

Write-Host("C")

# Variabler för att bygga up en CSV-fil genom Out-File
$filsökväg = "C:\my\file\path\Coolkids.csv"
$ColForetag = "Company"
$ColAnvandare = "Users"
$Emptyline = "`n"
$delimiter = ";"

for ($p = 1; $p -le $AA.Length; $p++) {

# writes out columns in the csv file
$ColForetag + $delimiter + $ColAnvandare | Out-File $filsökväg

# Writes out the domain name and the users
$OutputDomain + $delimiter + $OutputAnvandare | Out-File $filsökväg -Append

}
}

ReadInfo
Export

我的问题是,我无法导出用户或域。如您所见,我试图将变量设置为整个脚本的全局变量,但 $outputanvandare 和 $outputdomain 仅包含我在 foreach 循环中需要的信息。如果我尝试在其他任何地方打印它们,它们是空的?!

最佳答案

这个答案专注于变量范围 ,因为它是问题的直接原因。
不过值得一提的是最好避免从 开始跨范围修改变量;相反,通过成功流传递值(或者,不太常见的是通过引用变量和参数( [ref] )。

阐述PetSerAl's对这个问题的有用评论:关于 PowerShell 变量作用域的可能违反直觉的事情是:

  • 虽然您可以从祖先(更高)范围内看到(读取)变量 (例如父作用域)通过仅用名称(例如 $OutputDomain )来引用它们,
  • 你不能只用名字来修改它们 - 要修改它们,您必须明确引用它们定义的范围。

  • 如果没有范围限定,分配给在祖先范围中定义的变量会隐式地在当前范围中创建一个具有相同名称的新变量。

    示例 这证明了这个问题:
      # Create empty script-level var.
    Set-Variable -Scope Script -Name OutputDomain -Value 'original'
    # This is the same as:
    # $script:OutputDomain = 'original'

    # Declare a function that reads and modifies $OutputDomain
    function func {

    # $OutputDomain from the script scope can be READ
    # without scope qualification:
    $OutputDomain # -> 'original'

    # Try to modify $OutputDomain.
    # !! Because $OutputDomain is ASSIGNED TO WITHOUT SCOPE QUALIFICATION
    # !! a NEW variable in the scope of the FUNCTION is created, and that
    # !! new variable goes out of scope when the function returns.
    # !! The SCRIPT-LEVEL $OutputDomain is left UNTOUCHED.
    $OutputDomain = 'new'

    # !! Now that a local variable has been created, $OutputDomain refers to the LOCAL one.
    # !! Without scope qualification, you cannot see the script-level variable
    # !! anymore.
    $OutputDomain # -> 'new'
    }

    # Invoke the function.
    func

    # Print the now current value of $OutputDomain at the script level:
    $OutputDomain # !! -> 'original', because the script-level variable was never modified.

    解决方案:

    有几个 向变量引用添加范围限定的方法 :
  • 使用 范围修饰符 ,如 script $script:OutputDomain .
  • 在手头的情况下,这是最简单的解决方案:$script:OutputDomain = 'new'
  • 请注意,这只适用于 绝对 范围 global , script , 和 local (默认)。
  • 一个 警告 global变量 :它们是 session 全局的,因此分配给全局变量的脚本可能会无意中修改预先存在的全局变量,相反,在脚本中创建的全局变量在脚本终止后继续存在。
  • 使用 Get/Set-Variable -Scope ,除了支持绝对范围修饰符之外,它还支持 相对 按从 0 开始的索引的范围引用,其中 0表示当前范围,1父作用域等等。
  • 在手头的情况下,由于脚本范围是下一个更高的范围,Get-Variable -Scope 1 OutputDomain$script:OutputDomain 相同, 和Set-Variable -Scope 1 OutputDomain 'new'等于 $script:OutputDomain = 'new' .
  • (在函数和陷阱处理程序中很少使用的替代方法是使用 [ref] ,它允许在定义它的最直接的祖先范围内修改变量: ([ref] $OutputDomain).Value = 'new' ,正如 PetSerAl 在评论中指出的那样,它是同 (Get-Variable OutputDomain).Value = 'new' )

  • 有关更多信息,请参阅:
  • Get-Help about_Variables
  • Get-Help about_Scopes


  • 最后,为了完整起见, Set-Variable -Option AllScope是一种完全避免使用范围限定的方法 (在所有后代范围内),因为实际上只有一个同名的变量存在,可以在任何(后代)范围内读取和修改而无需范围限定。
      # By defining $OutputDomain this way, all descendent scopes
    # can both read and assign to $OutpuDomain without scope qualification
    # (because the variable is effectively a singleton).
    Set-Variable -Scope Script -Option AllScope -Name OutputDomain

    但是, 我不会推荐它 (至少在不采用命名约定的情况下并非如此),因为它模糊了修改局部变量和全范围变量之间的区别:
    在没有范围限定的情况下,查看诸如 $OutputDomain = 'new' 之类的语句孤立地看,您无法判断是修改了局部变量还是全范围变量。

    关于powershell - 无法从函数内部修改脚本范围的变量,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/38661343/

    25 4 0
    Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
    广告合作:1813099741@qq.com 6ren.com