在 PowerShell 脚本中处理数组
Handling Array in PowerShell Script
我编写了 PowerShell 脚本来自动执行一些 AD 命令。这是脚本。
$usergroup="TACACS Admins"
$computerrole="1626-APPCONF"
$zone="AWS"
$username="<>"
$password="<>";
[String[]] $HostServers ='smp001-01','sl1ps01-13-9';
$ValidatedHostServers = @()
$NotValidatedHostServers = @()
Import-Module ActiveDirectory
Import-Module Centrify.DirectControl.PowerShell
$Password = ConvertTo-SecureString $password -AsPlainText -Force
$Cred = New-Object System.Management.Automation.PSCredential($username,$Password)
Set-CdmCredential -Domain <> -Credential $Cred
function Add-HostComputer{
Param($cred,$zone,$computerrole,$ValidatedHostServers)
# Get Computer Role
$GroupName = Get-ADGroup -Identity $computerrole
Write-Output $GroupName
foreach($Host in $ValidatedHostServers)
{
#Get -Member
$DistinguishedName = Get-ADComputer -Identity $Host
Write-Output $ValidatedHostServers
#Add $Hostserver to $comprole computer Role
$Output = Add-ADGroupMember -Identity $GroupName -Members $DistinguishedName -Credential $Cred
}
}
function ValidateHost{
Param($HostServers)
foreach($HostName in $HostServers)
{
try{
$HostOutput = Get-ADComputer -Identity $HostName -ErrorAction SilentlyContinue
$ValidatedHostServers += $HostName
}
catch
{
$NotValidatedHostServers += $HostName
}
}
Write-Host $ValidatedHostServers
$Result = @{"Valid_hosts"=$ValidatedHostServers;"Invalid_hosts"=$NotValidatedHostServers} | ConvertTo-Json -Compress
Write-Host $Result
Write-Host $ValidatedHostServers.Count
If($ValidatedHostServers.Count -ne 0)
{
Write-Host $ValidatedHostServers
Add-HostComputer -Cred $Cred -zone $zone -computerrole $computerrole -
ValidatedHostServers $ValidatedHostServers
}
}
$Final = ValidateHost -HostServers $HostServers
Write-Host $Final
我尝试编写主机输入,发现 $ValidatedHostServers 数组不是数组形式。我可能是我在语法上遗漏了一些东西。
数组中有两个值但是
Write-Host $ValidatedHostServers.Count display as 1.
在此先感谢您的帮助。
这是 powerShell 中显示的错误
smp001-01sl1ps01-13-9
{"Invalid_hosts":[],"Valid_hosts":"smp001-01sl1ps01-13-9"}
1
smp001-01sl1ps01-13-9
Cannot overwrite variable Host because it is read-only or constant.
At line:27 char:9 + foreach($Host in $ValidatedHostServers) + CategoryInfo : WriteError: (Host:String) [], SessionStateUnauthorizedAccessException + FullyQualifiedErrorId : VariableNotWritable
CN=1626-APPCONF,OU=Role Groups-
Computer,OU=Centrify,OU=Operations,DC=qateradatacloud,DC=com
尝试这种方式,获取列表然后遍历它:
function ValidateHost{
Param($HostServers)
#
$GroupName = Get-ADGroup -Identity $computerrole
#
# Get server validation list
$CheckedServers = $HostServers | ForEach-Object {
Try {
$HostOutput = Get-ADComputer -Identity $_ -ErrorAction Stop
$Validated = $true
}
Catch {
$Validated = $false
}
[pscustomobject]@{HostName = $_;Validated = $Validated}
}
# Add-HostComputer
# Iterate over list of validated servers
$CheckedServers | Where-Object { $_.Validated -eq $true } | ForEach-Object {
Try {
$DistinguishedName = Get-ADComputer -Identity $_.HostName -ErrorAction Stop
$Output = Add-ADGroupMember -Identity $GroupName -Members $DistinguishedName -Credential $Cred -ErrorAction Stop
}
Catch {
$Output = $_
}
[pscustomobject]@{HostName = $_.HostName;DN = $DistinguishedName;Result = $output}
}
}
如果您将代码减少到可重现该行为的最小脚本,您将得到如下结果:
$ValidatedHostServers = @( "xxx" );
function ValidateHost
{
write-host "inside before = '$($ValidatedHostServers | ConvertTo-Json)'";
$ValidatedHostServers += "smp001-01";
$ValidatedHostServers += "sl1ps01-13-9";
write-host "inside after = '$($ValidatedHostServers | ConvertTo-Json)'";
write-host ($ValidatedHostServers | ConvertTo-Json)
}
write-host "value before = '$($ValidatedHostServers | ConvertTo-Json)'";
ValidateHost;
write-host "value after = '$($ValidatedHostServers | ConvertTo-Json)'";
输出如下:
value before = '"xxx"'
inside before = '"xxx"'
inside after = '"smp001-01sl1ps01-13-9"'
value after = '"xxx"'
我认为这里发生了两件事:
- 您的函数在 child scope 中执行,因此在函数内部对父作用域(即 $ValidatedHostServer)中定义的变量所做的更改在函数退出时不会继续存在 - 请参阅子作用域的引用 link:
items that you create and change in the child scope do not affect the parent scope,
unless you explicitly specify the scope when you create the items.
- 在 assignment by addition operator(即“+=”)中的 PowerShell 中可能存在一个错误,当它首先为子范围中的父变量赋值时 - 它基本上将 $ValidatedHostServers 视为undefined 并将其转换为字符串,然后导致第二个 += 进行字符串连接而不是数组追加。
您可以像这样解决这两个问题:
#$ValidatedHostServers = @( "xxx" ); <- replace this with the next line
Set-Variable -Name "ValidatedHostServers" -Option AllScope -Value @( "xxx" );
"AllScope" 选项允许子作用域(即函数)修改父作用域中的变量,这样您的更改将在函数存在后保留。它还 side-steps "assignment by addition operator" 中的潜在错误。
Set-Variable -Name "ValidatedHostServers" -Option AllScope -Value @( "xxx" );
function ValidateHost
{
write-host "inside before = '$($ValidatedHostServers | ConvertTo-Json)'";
$ValidatedHostServers += "smp001-01";
$ValidatedHostServers += "sl1ps01-13-9";
write-host "inside after = '$($ValidatedHostServers | ConvertTo-Json)'";
write-host ($ValidatedHostServers | ConvertTo-Json)
}
write-host "value before = '$($ValidatedHostServers | ConvertTo-Json)'";
ValidateHost;
write-host "value after = '$($ValidatedHostServers | ConvertTo-Json)'";
然后我们得到这个输出
value before = '"xxx"'
inside before = '"xxx"'
inside after = '[
"xxx",
"smp001-01",
"sl1ps01-13-9"
]'
[
"xxx",
"smp001-01",
"sl1ps01-13-9"
]
value after = '[
"xxx",
"smp001-01",
"sl1ps01-13-9"
]'
更新
PowerShell github 存储库中的相关问题:
我编写了 PowerShell 脚本来自动执行一些 AD 命令。这是脚本。
$usergroup="TACACS Admins"
$computerrole="1626-APPCONF"
$zone="AWS"
$username="<>"
$password="<>";
[String[]] $HostServers ='smp001-01','sl1ps01-13-9';
$ValidatedHostServers = @()
$NotValidatedHostServers = @()
Import-Module ActiveDirectory
Import-Module Centrify.DirectControl.PowerShell
$Password = ConvertTo-SecureString $password -AsPlainText -Force
$Cred = New-Object System.Management.Automation.PSCredential($username,$Password)
Set-CdmCredential -Domain <> -Credential $Cred
function Add-HostComputer{
Param($cred,$zone,$computerrole,$ValidatedHostServers)
# Get Computer Role
$GroupName = Get-ADGroup -Identity $computerrole
Write-Output $GroupName
foreach($Host in $ValidatedHostServers)
{
#Get -Member
$DistinguishedName = Get-ADComputer -Identity $Host
Write-Output $ValidatedHostServers
#Add $Hostserver to $comprole computer Role
$Output = Add-ADGroupMember -Identity $GroupName -Members $DistinguishedName -Credential $Cred
}
}
function ValidateHost{
Param($HostServers)
foreach($HostName in $HostServers)
{
try{
$HostOutput = Get-ADComputer -Identity $HostName -ErrorAction SilentlyContinue
$ValidatedHostServers += $HostName
}
catch
{
$NotValidatedHostServers += $HostName
}
}
Write-Host $ValidatedHostServers
$Result = @{"Valid_hosts"=$ValidatedHostServers;"Invalid_hosts"=$NotValidatedHostServers} | ConvertTo-Json -Compress
Write-Host $Result
Write-Host $ValidatedHostServers.Count
If($ValidatedHostServers.Count -ne 0)
{
Write-Host $ValidatedHostServers
Add-HostComputer -Cred $Cred -zone $zone -computerrole $computerrole -
ValidatedHostServers $ValidatedHostServers
}
}
$Final = ValidateHost -HostServers $HostServers
Write-Host $Final
我尝试编写主机输入,发现 $ValidatedHostServers 数组不是数组形式。我可能是我在语法上遗漏了一些东西。
数组中有两个值但是
Write-Host $ValidatedHostServers.Count display as 1.
在此先感谢您的帮助。
这是 powerShell 中显示的错误
smp001-01sl1ps01-13-9
{"Invalid_hosts":[],"Valid_hosts":"smp001-01sl1ps01-13-9"}
1
smp001-01sl1ps01-13-9
Cannot overwrite variable Host because it is read-only or constant.
At line:27 char:9 + foreach($Host in $ValidatedHostServers) + CategoryInfo : WriteError: (Host:String) [], SessionStateUnauthorizedAccessException + FullyQualifiedErrorId : VariableNotWritable
CN=1626-APPCONF,OU=Role Groups-
Computer,OU=Centrify,OU=Operations,DC=qateradatacloud,DC=com
尝试这种方式,获取列表然后遍历它:
function ValidateHost{
Param($HostServers)
#
$GroupName = Get-ADGroup -Identity $computerrole
#
# Get server validation list
$CheckedServers = $HostServers | ForEach-Object {
Try {
$HostOutput = Get-ADComputer -Identity $_ -ErrorAction Stop
$Validated = $true
}
Catch {
$Validated = $false
}
[pscustomobject]@{HostName = $_;Validated = $Validated}
}
# Add-HostComputer
# Iterate over list of validated servers
$CheckedServers | Where-Object { $_.Validated -eq $true } | ForEach-Object {
Try {
$DistinguishedName = Get-ADComputer -Identity $_.HostName -ErrorAction Stop
$Output = Add-ADGroupMember -Identity $GroupName -Members $DistinguishedName -Credential $Cred -ErrorAction Stop
}
Catch {
$Output = $_
}
[pscustomobject]@{HostName = $_.HostName;DN = $DistinguishedName;Result = $output}
}
}
如果您将代码减少到可重现该行为的最小脚本,您将得到如下结果:
$ValidatedHostServers = @( "xxx" );
function ValidateHost
{
write-host "inside before = '$($ValidatedHostServers | ConvertTo-Json)'";
$ValidatedHostServers += "smp001-01";
$ValidatedHostServers += "sl1ps01-13-9";
write-host "inside after = '$($ValidatedHostServers | ConvertTo-Json)'";
write-host ($ValidatedHostServers | ConvertTo-Json)
}
write-host "value before = '$($ValidatedHostServers | ConvertTo-Json)'";
ValidateHost;
write-host "value after = '$($ValidatedHostServers | ConvertTo-Json)'";
输出如下:
value before = '"xxx"'
inside before = '"xxx"'
inside after = '"smp001-01sl1ps01-13-9"'
value after = '"xxx"'
我认为这里发生了两件事:
- 您的函数在 child scope 中执行,因此在函数内部对父作用域(即 $ValidatedHostServer)中定义的变量所做的更改在函数退出时不会继续存在 - 请参阅子作用域的引用 link:
items that you create and change in the child scope do not affect the parent scope, unless you explicitly specify the scope when you create the items.
- 在 assignment by addition operator(即“+=”)中的 PowerShell 中可能存在一个错误,当它首先为子范围中的父变量赋值时 - 它基本上将 $ValidatedHostServers 视为undefined 并将其转换为字符串,然后导致第二个 += 进行字符串连接而不是数组追加。
您可以像这样解决这两个问题:
#$ValidatedHostServers = @( "xxx" ); <- replace this with the next line
Set-Variable -Name "ValidatedHostServers" -Option AllScope -Value @( "xxx" );
"AllScope" 选项允许子作用域(即函数)修改父作用域中的变量,这样您的更改将在函数存在后保留。它还 side-steps "assignment by addition operator" 中的潜在错误。
Set-Variable -Name "ValidatedHostServers" -Option AllScope -Value @( "xxx" );
function ValidateHost
{
write-host "inside before = '$($ValidatedHostServers | ConvertTo-Json)'";
$ValidatedHostServers += "smp001-01";
$ValidatedHostServers += "sl1ps01-13-9";
write-host "inside after = '$($ValidatedHostServers | ConvertTo-Json)'";
write-host ($ValidatedHostServers | ConvertTo-Json)
}
write-host "value before = '$($ValidatedHostServers | ConvertTo-Json)'";
ValidateHost;
write-host "value after = '$($ValidatedHostServers | ConvertTo-Json)'";
然后我们得到这个输出
value before = '"xxx"'
inside before = '"xxx"'
inside after = '[
"xxx",
"smp001-01",
"sl1ps01-13-9"
]'
[
"xxx",
"smp001-01",
"sl1ps01-13-9"
]
value after = '[
"xxx",
"smp001-01",
"sl1ps01-13-9"
]'
更新
PowerShell github 存储库中的相关问题: