Powershell удаленный статический IP через скрипт
Я собираюсь написать функцию 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-адрес и маску подсети. Там не было шлюза по умолчанию (что имеет смысл, так как я не зашел так далеко в сценарии). Компьютер, о котором идет речь, не имел доступа к сети, поскольку отсутствовал шлюз по умолчанию.
Я также пробовал запускать те же команды из интерактивной оболочки, и та же самая "заморозка" происходит на том же самом команда:
$wmi.EnableStatic($IPAddress, $SubnetMask)
Мое лучшее предположение заключается в том, что изменение конфигурации сетевого адаптера нарушает удаленное соединение WMI. Есть ли способ сделать это так, чтобы я мог написать сценарий назначения статического IP-адреса 100% удаленно?
Edit: I MacGyvered еще одна попытка, которая создает объект ScriptBlock и отправляет его на удаленный компьютер с помощью команды Invoke. Мне пришлось проделать кое-какую интересную работу ногами, чтобы получить массив 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
}
2 ответа:
Возможно, Вам повезет больше, если вы используете Invoke-Command для запуска netsh на удаленном компьютере, который устанавливает IP-адрес, маску подсети и шлюз в одной команде. Однако netsh использует другое имя для интерфейса, которое можно получить из свойства NetConnectionID класса Win32_NetworkAdapter.
$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
To
$wmi = Get-WmiObject Win32_NetworkAdapterConfiguration -ComputerName $ComputerName -Filter "IPEnabled = 'True'" -Credential $Credential | select -First 1
Это гарантирует, что вы получаете только один объект, но, конечно, он не может гарантировать, что это обязательно тот, который вы хотите, если есть более одного с IPEnabled true.
Я бы вызвал вашу функцию в скрипте, который использует
localHost
в качестве параметра$computername
, а затем удаленно выполнил (invoke-command
) этот скрипт на удаленном компьютере, используя удаленные сеансы powershell (New-PSSession
) или создав удаленный процесс PowerShell с этим скриптом в качестве параметра с помощью WMI (в этом случае вам нужно скопировать srcript на удаленный комптер).Вы также можете запланировать этот сценарий на удаленном компьютере ... общая идея заключается в том, чтобы не использовать сеть во время работы.