我希望编写一个Powershell函数,将远程IP地址远程分配给运行时指定的计算机。我做了一些研究,发现了Win32_NetworkAdapterConfiguration类,这看起来就像我需要的那样。所以我坐下来给自己写了一个函数:
Function Set-StaticIPAddress
{
param
(
[Parameter(Mandatory = $true,
Position = 0,
ValueFromPipeline = $true,
ValueFromPipelineByPropertyName = $true)]
[String] $ComputerName
,
[Parameter(Mandatory = $true,
Position = 1)]
[Alias("IPv4Address")]
[String] $IPAddress
,
[Parameter(Position = 2)]
[String] $SubnetMask = "none"
,
[Parameter(Position = 3)]
[String] $DefaultGateway = "none"
,
[Parameter(Position = 4)]
[String[]] $DNSServers = ("172.16.1.36","172.16.1.78")
,
[Parameter(Position = 5)]
[PSCredential] $Credential
)
process
{
# There's some error-checking here that I've snipped out for convenience
Write-Verbose "Testing connection to $ComputerName"
if (-not (Test-Connection $ComputerName))
{
Write-Error "Unable to connect to $ComputerName."
return
}
Write-Verbose "Obtaining remote WMI reference"
if ($Credential)
{
$wmi = Get-WmiObject Win32_NetworkAdapterConfiguration -ComputerName $ComputerName -Filter "IPEnabled = 'True'" -Credential $Credential
} else {
$wmi = Get-WmiObject Win32_NetworkAdapterConfiguration -ComputerName $ComputerName -Filter "IPEnabled = 'True'"
}
Write-Verbose "Attempting to set DNS servers"
$wmi.SetDNSServerSearchOrder($DNSServers)
Write-Verbose "Attempting to set dynamic DNS registration"
$wmi.SetDynamicDNSRegistration($true)
Write-Verbose "Attempting to set static IP address and subnet mask"
$wmi.EnableStatic($IPAddress, $SubnetMask)
Clear-DnsClientCache #This may not be necessary; I added it as a troubleshooting step
Write-Verbose "Attempting to set default gateway"
$wmi.SetGateways($DefaultGateway, 1)
Write-Output $wmi
}
}
麻烦的是, EnableStatic 方法似乎永远不会返回一个值 - 成功或失败代码。我在一台坐在我旁边的机器上测试了这个功能,而脚本仍在等待"尝试设置静态IP地址和子网掩码"阶段,我拉起了机器上的配置,发现了静态IP和子网掩码集。没有默认网关(这是有道理的,因为我在脚本中没有那么远)。有问题的计算机没有网络访问权限,因为缺少默认网关。
我也试过从交互式shell运行相同的命令,同样的"冻结"发生在同一个命令上:
$wmi.EnableStatic($IPAddress, $SubnetMask)
我最好的猜测是,更改网络适配器配置会破坏远程WMI连接。有没有办法让这项工作成功,所以我可以100%远程编写静态IP地址的分配?
编辑:我MacGyvered另一次创建ScriptBlock对象并使用Invoke-Command将其发送到远程计算机的尝试。我不得不做一些有趣的步法来获得一个IP地址数组转换成字符串文字,包括引号,但我现在可以确认脚本块具有正确的语法和所有这些。不幸的是,这样做会导致我的PS窗口抱怨网络连接已丢失(因为IP地址已更改)并且脚本块未成功完成。
$wmiLiteral = '$wmi' # used so the script block actually creates and references a variable, $wmi
$script =
"$wmiLiteral = Get-WmiObject Win32_NetworkAdapterConfiguration -Filter ""IPEnabled = 'True'"";
$wmiLiteral.EnableStatic(""$IPAddress"", ""$SubnetMask"");
$wmiLiteral.SetGateways(""$DefaultGateway"", 1);
$wmiLiteral.SetDNSServerSearchOrder($DNSServersList);
Write-Output $wmiLiteral"
Write-Verbose "Script block:`n-------------`n$script`n---------------"
$scriptBlock = [scriptblock]::Create($script)
Write-Verbose "Testing connection to $ComputerName"
if (-not (Test-Connection $ComputerName))
{
Write-Error "Unable to connect to $ComputerName."
return
}
Write-Verbose "Invoking scriptblock"
if ($Credential)
{
$output = Invoke-Command -ComputerName $ComputerName -ScriptBlock $scriptBlock -Credential $Credential
} else {
$output = Invoke-Command -ComputerName $ComputerName -ScriptBlock $scriptBlock
}
答案 0 :(得分:1)
我会在一个使用localHost
作为$computername
参数的脚本中调用您的函数,然后使用powershell远程会话远程执行(invoke-command
)远程计算机上的此脚本({{ 1}}),或使用此脚本创建一个远程PowerShell进程作为WMI参数(在这种情况下,您必须复制远程计算机上的srcript)。
您也可以在远程计算机上安排此脚本...一般的想法是在操作期间不使用网络。
答案 1 :(得分:1)
使用 Invoke-Command 在远程计算机上运行 netsh 可能会更加幸运,它可以在一个命令中设置IP地址,子网掩码和网关。但是, netsh 会为界面使用不同的名称,您可以从 Win32_NetworkAdapter 类的 NetConnectionID 属性中获取该名称。
$InterfaceName = $Get-WmiObject Win32_NetworkAdapter | ?{$_.Description -eq $wmi.Description} | select -ExpandProperty NetConnectionID
Invoke-Command -ComputerName $ComputerName -Credential $Credential -ScriptBlock {netsh interface ip set address $InterfaceName static $IPAddress $SubnetMask $DefaultGateway 1}
您可以将第二行包装在另一个if ($Credential)
块中。
但是,我强烈建议您验证过滤器是否返回一个对象而不是一个对象数组,如上面的评论所示。或者,为了安全起见,请更改
$wmi = Get-WmiObject Win32_NetworkAdapterConfiguration -ComputerName $ComputerName -Filter "IPEnabled = 'True'" -Credential $Credential
到
$wmi = Get-WmiObject Win32_NetworkAdapterConfiguration -ComputerName $ComputerName -Filter "IPEnabled = 'True'" -Credential $Credential | select -First 1
这将确保您只获得一个对象,但当然如果有多个 IPEnabled 为true,则无法确保它必然是您想要的对象。