[英]Passing a PowerShell variable as a cmdlet parameter
我正在学习PowerShell为我的团队编写工具。 今天我处于紧要关头并且工作正常,但我希望通过删除ForEach循环中的IF语句来简化它,因为命令之间的唯一区别是参数-replace或-remove 。
Write-Host "This script removes or replaces en masse users' msds-SyncServerURL property"
DO {
$TargetSSU=Read-Host "`nWhat msds-SyncServerURL do you want to replace or remove?"
$UsersToBeFixed=Get-ADUser -Filter {msds-SyncServerURL -like $TargetSSU} -Properties ('name','samaccountname','msDS-SyncServerURL')
IF ($UsersToBeFixed -eq $null) {
Write-Host "`nNo users appear to have $TargetSSU as their msds-SyncServerURL value. Please try again."
}
} UNTIL ($UsersToBeFixed -ne $null)
Write-Host "`n`nThe following users have $TargetSSU as their msds-SyncServerURL value:"
$UsersToBeFixed |select name,samaccountname,msds-syncserverurl|ft
DO {
$Action=Read-Host "Do you want to [R]emove or [U]pdate $TargetSSU?"
} Until (($Action -eq "R") -or ($Action -eq "U"))
IF ($Action -eq "U") {
DO {
$NewSyncServer=Read-Host "`nEnter the new Sync Server's hostname (not the URL)"
Write-Host "`nChecking to see if $NewSyncServer has a userfile share..."
$VerifySyncServer=Test-Path \\$NewSyncServer\userfiles
IF ($VerifySyncServer -eq $false) {
Write-host "`n$NewSyncServer does not appear to be a valid Sync Server hostname. Please try again."
}
} UNTIL ($VerifySyncServer -eq $true)
$TargetSSU="https://$NewSyncServer.ourdomain.com"
}
ForEach ($userToBeFixed in $UsersToBeFixed) {
Write-Host "`nFixing" ($usertobefixed).name
IF ($Action -eq "R") {
Set-ADObject -identity $userToBeFixed -remove @{"msDS-SyncServerUrl" = $TargetSSU}
}
IF ($Action -eq "U") {
Set-ADObject -identity $userToBeFixed -replace @{"msDS-SyncServerUrl" = $TargetSSU}
}
}
Write-Host "`nHere is the result of the operation:"
foreach ($userToBeFixed in $UsersToBeFixed) {
Get-ADUser -Identity $userToBeFixed -Properties ('name','samaccountname','msDS-SyncServerURL')|select name,samaccountname,msds-syncserverurl
}
我最初有以下开关,尝试各种引号的排列,甚至{$ action =“replace”}:
Switch($action)
{
R {'remove'}
U {'replace'}
}
我还在ForEach循环中尝试了Invoke-Expression:
$CMD="Set-ADObject -identity $userToBeFixed -$action @{`"msDS-SyncServerUrl`" = $TargetSSU}"
Invoke-Expression -Command $CMD
Set-ADObject cmdlet总是会失败,通常抱怨Set-ADObject无法找到接受“-remove”,“System.Object []”或“System.Collections.Hashtable”等参数的位置参数。
我将问题隔离到Set-ADObject,而不是喜欢用作参数的$ action变量。 如果我用-replace或-remove替换- $ action它会起作用(就像在上面的代码片段中一样)。
我意识到这是一个小问题,但是因为看似没有理由而让我有这样的冗余代码。 我很想学习如何解决这个问题。
另外,无关,我还没有找到更好的方法来做到这一点:
Until (($Action -eq "R") -or ($Action -eq "U"))
我搜索并尝试过其他解决方案,例如:
Until ($Action -eq @{"R" -or "U"})
但似乎无法巩固多种条件的评估。 这让我感到困扰,但不像我的主要问题那么多。
请放轻松我。 我对这整件事情都很陌生。 如果有人看到任何其他我可以提高让我知道。 我想学习这个。
谢谢。
你可以用splatting来解决这个问题。
例如:
$action = 'Recurse'
$params = @{ $action = $true }
Get-ChildItem @params
该示例在功能上等同于Get-ChildItem -Recurse
Persistent13的有用答案向您展示了如何使用splatting通过哈希表动态传递参数。
至于:
另外,无关,我还没有找到更好的方法来做到这一点:
Until (($Action -eq "R") -or ($Action -eq "U"))
PowerShell中提供阵列遏制操作符: -contains
(PSV1 +,阵列上的左轴)和-in
(PSv3 +,阵列上的RHS):
# PSv3+
$Action -in 'R', 'U'
# Equivalent, PSv1+
'R', 'U' -contains $Action
两种形式都将标量操作数与数组操作数的每个元素进行比较(使用-eq
逻辑),并在找到第一个匹配(如果有)时立即返回$True
。
另一种选择是使用带有正则表达式的-match
运算符:
$Action -match '^(R|U)$'
我喜欢将不涉及脚本逻辑的所有内容(即函数)移动到与PowerShell主脚本不同的文件中。 我的大多数脚本都遵循以下结构:
Edit-SyncServerUrl.ps1
#requires -Version 5.1
<#
Company header
#>
<#
.SYNOPSIS
Comment-based help
#>
[CmdletBinding(SupportsShouldProcess)]
Param([String]$Option)
. "$PSScriptRoot\scriptfunctions.ps1"
<# .. variables .. #>
Switch -Regex ($Option)
{
'^rem' {Edit-SyncServerURL -Remove}
'^rep' {Edit-SyncServerURL -Replace}
Default {Write-Host "Invalid option passed: $Option"}
}
在您的具体示例中,我会将提示设置等的所有逻辑带入一个函数,该函数根据传递给它的参数选择执行路径。 你可以做到
Param(
[ValidateScript({$_ -match '^(u|r)'})]
[String]$Option=(Read-Host -Prompt 'Would you like to (r)emove or (u)pdate a target msds-SyncServerUrl?'
)
Switch -Regex ($Option)
{
'^r' { <# Logic #> }
'^u' { <# Logic #> }
}
Persistent13对如何splat参数需要哈希表的解释就是那里的诀窍。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.