Powershell通过脚本远程静态IP

Powershell通过脚本远程静态IP,powershell,wmi,Powershell,Wmi,我希望编写一个Powershell函数,将静态IP地址远程分配给运行时指定的计算机。我做了一些研究,找到了Win32_NetworkAdapterConfiguration类,这似乎正是我需要的。于是我坐下来给自己写了一个函数: Function Set-StaticIPAddress { param ( [Parameter(Mandatory = $true, Position = 0,

我希望编写一个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地址的分配编写脚本

Edit:I macgy再次尝试创建ScriptBlock对象,并使用Invoke命令将其发送到远程计算机。我不得不做一些有趣的准备工作,将IP地址数组转换为字符串文字,包括引号,但现在我可以确认脚本块的语法正确。不幸的是,这样做会导致my PS window抱怨网络连接已丢失(因为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
}

我将在使用
localHost
作为
$computername
参数的脚本中调用您的函数,然后使用powershell远程会话(
New PSSession
)在远程计算机上远程执行(
invoke command
)此脚本,或者使用此脚本作为WMI参数创建远程powershell进程(在这种情况下,您必须在远程计算机上复制srcript)


您也可以在远程计算机上计划此脚本…一般的想法是在操作期间不使用网络。

您可能更幸运地使用调用命令在远程计算机上运行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


这将确保您只获得一个对象,但当然,如果有多个对象具有i启用true,则无法确保它一定是您想要的对象。

好吧,首先,您的脚本假定您的筛选器始终只返回一个对象,但它可以返回一个对象数组。除此之外,您的理论是正确的nds似乎合理。请尝试以下操作:在调用EnableStatic方法之前,将正在查看的适配器的描述存储在变量中:
$description=$wmi.description
在调用EnableStatic后,再次获取wmi对象:
$wmi=get WMIOObject Win32_NetworkAdapterConfiguration-Filter“description=$description”
感谢您的回复,但这并没有什么区别。我无法让脚本首先通过EnableStatic方法调用。即使之后的Write Verbose cmdlet也不会执行。如果您先运行EnableStatic,然后再运行其他方法呢?在浏览了其他一些脚本后,似乎是其中之一还有,你在多台机器上试过这个吗?这是唯一一台有问题的机器吗?@JoshuaT为了确保我们没有在这个机器上转动轮子,你验证过过滤器只返回一个对象吗?在运行Get-WMIOObject的if块之后,添加
$wmi.GetType().BaseType;return
,看看它是否输出“System.Management.ManagementBaseObject”或“System.Array”。(然后删除该行)是的,我已经在用于测试的机器上手动测试了WMI查询,它只返回一个结果。但在大规模使用该查询之前,我肯定需要执行该错误检查:)感谢您的回复。:)我试图调整脚本以使用Invoke命令和脚本块,但未能成功完成整个块。(编辑:请参阅问题中的其他信息。)我真的不想将脚本复制到需要使用的每台机器上……这是真正使其在本地运行的唯一方法吗?首先创建一个脚本(.ps1)可以使用“localhost”执行您想要的操作"。然后将脚本保留在管理器计算机上,并使用PSSession。将脚本放入Invoke命令的filepath参数中,使用此参数时,Windows PowerShell会将指定脚本文件的内容转换为脚本块,将脚本块传输到远程计算机,并在远程计算机上运行。我没有得到他的方法很有效,但由于我的目标是Powershell函数,所以我不想再处理另一个浮动的脚本。不过,将来了解这种技术会很有帮助。感谢您的帮助!尝试执行此操作时,我收到一条错误消息:“文件名、目录名或卷标语法不正确。”听起来好像我在某处缺少引号,但是使用这样的Invoke命令,我不确定如何显示它正在运行的实际命令。
Invoke命令-ComputerName$ComputerName-ScriptBlock{netsh接口
$wmi = Get-WmiObject Win32_NetworkAdapterConfiguration -ComputerName $ComputerName -Filter "IPEnabled = 'True'" -Credential $Credential | select -First 1