Summary: Learn how to use Windows PowerShell to configure a remote computer’s network adapter to wake the computer.
Hey, Scripting Guy! At work, we have been trying to get our automation solution put into place. One problem is that on many of the computers, the network adapter is not configured to allow it to wake up the machine. This means that when someone shuts down the computer in the evening, that is it until the next day. I would like to be able to do maintenance at night when the users have gone home, but to do so, I need to be able to wake up the computer. I found an article on the Internet, but basically the article talked about hacking the registry, and I did not feel like I could trust the article. Can Windows PowerShell configure a computer’s network card to allow it to wake up the computer?
—TS
Hello TS,
Microsoft Scripting Guy Ed Wilson here. One thing to keep in mind about Windows PowerShell is that it can only do what is available. In other words, if no mechanism exists for automating a particular problem, Windows PowerShell will not be able to automate a solution. Windows PowerShell can certainly make working with registry keys easier because of the existence of the registry provider, and it can make working with WMI classes easier as well. However, if the underlying technology does not expose the functionality, we are out of luck.
TS, in this particular case, I am not certain you are out of luck. I was looking over my list of WMI classes that have settable properties and implemented methods, and I ran across the MSPower_DeviceWakeEnable WMI class. This particular WMI class exists in the Root\WMI namespace, and is not documented on MSDN. Because the WMI class is not documented, this means that it is not supported. It does not mean that it will not work, but that it is not supported. As a matter of a fact, it does not work on my Windows 7 Ultimate 64-bit desktop computer; I believe that is because I have a custom network adapter card driver that supports port teaming for better throughput.
The WMI class does work on my 32-bit Windows 2008 server, which is using an inbox network card driver. Because the class is not documented, it means that I cannot tell you if the class exists on Windows XP or Windows Server 2003. I know it exists on Windows Server 2008 R2, Windows Server 2008, and Windows 7.
TS, I am going to show you how to use the MSPower_DeviceWakeEnable WMI class to enable the network card to wake the machine. If the technique does not work on all your devices, there is nothing I can do—the class is unsupported (although you might be able to use the powercfg utility to configure your network cards to wake up the computer).
The first thing I need to do is to store credentials for my remote WMI connection. Remember, I am working against a remote server. I use the Get-Credential cmdlet to retrieve the credentials for the remote computer, and I store the returned credential object in the $cred variable. This is shown here:
$cred = Get-Credential nwtraders\administrator
Next, I use WMI and the Get-WmiObject cmdlet to look for a network card on the remote server that is netenabled. This property of the Win32_NetworkAdapter class should return True only if the network interface is enabled. If there are multiple network cards that are enabled, you might want to query for the NetConnectionStatus of 2 (means that it is connected). If you are still having difficulity finding the correct network adapter, you might want to try the netconnectionid property. That is the name of the connection (for example “Local Area Connection”), and if you have named all your network adapters the same, it will be easy to pick them up with this property.
When I query the netenabled property on my remote server, only one network adapter is returned. The command and associated output are shown here:
PS C:\> gwmi win32_networkadapter -filter “netenabled = ‘true'” -cn dc1 -cred $cred
ServiceName : E100B
MACAddress : 00:07:E9:7C:A7:5F
AdapterType : Ethernet 802.3
DeviceID : 6
Name : Intel(R) PRO/100 VE Network Connection
NetworkAddresses :
Speed : 100000000
Now I repeat the above command, and store the returned WMI object in a variable named $nic. This command is shown here:
$nic= gwmi win32_networkadapter -filter “netenabled = ‘true'” -cn dc1 -cred $cred
I next query the MSPower_DeviceWakeEnable WMI class to see what type of date it returns. The WMI class resides in the Root\WMI namespace, so I need to specify the namespace parameter when making the query. I am still working on a remote machine, so I also specify the computername (alias is cn) and the credential (shortened to cred) parameters. The command and associated output appear here.
PS C:\> gwmi MSPower_DeviceWakeEnable -Namespace root\wmi -cn dc1 -cred $cred
__GENUS : 2
__CLASS : MSPower_DeviceWakeEnable
__SUPERCLASS : MSPower
__DYNASTY : MSPower
__RELPATH : MSPower_DeviceWakeEnable.InstanceName=”PCI\\VEN_8086&DEV_105
0&SUBSYS_01571028&REV_02\\4&1c660dd6&0&40F0_0″
__PROPERTY_COUNT : 3
__DERIVATION : {MSPower}
__SERVER : DC1
__NAMESPACE : root\wmi
__PATH : \\DC1\root\wmi:MSPower_DeviceWakeEnable.InstanceName=”PCI\\V
EN_8086&DEV_1050&SUBSYS_01571028&REV_02\\4&1c660dd6&0&40F0_0
“
Active : True
Enable : True
InstanceName : PCI\VEN_8086&DEV_1050&SUBSYS_01571028&REV_02\4&1c660dd6&0&40
F0_0
__GENUS : 2
__CLASS : MSPower_DeviceWakeEnable
__SUPERCLASS : MSPower
__DYNASTY : MSPower
__RELPATH : MSPower_DeviceWakeEnable.InstanceName=”ACPI\\PNP0303\\4&1506
bb2e&0_0″
__PROPERTY_COUNT : 3
__DERIVATION : {MSPower}
__SERVER : DC1
__NAMESPACE : root\wmi
__PATH : \\DC1\root\wmi:MSPower_DeviceWakeEnable.InstanceName=”ACPI\\
PNP0303\\4&1506bb2e&0_0″
Active : True
Enable : False
InstanceName : ACPI\PNP0303\4&1506bb2e&0_0
The InstanceName properties look weird, but they also look familiar. They look like the PNPDeviceID property from the Win32_NetworkAdapter WMI class. I can therefore use the PNPDeviceID property value from my network adapter and filter out only a matching instance from the MSPower_DeviceWakeEnable WMI class. So I take the PNPDeviceID property value and attempt to use it in a Where-Object command. Unfortunately, an error results. The command and associated output are shown here.
PS C:\> gwmi MSPower_DeviceWakeEnable -Namespace root\wmi | where {$_.instancena
me -match $nic.PNPDeviceID }
Bad argument to operator ‘-match’: parsing “PCI\VEN_8086&DEV_1050&SUBSYS_015710
28&REV_02\4&1C660DD6&0&40F0″ – Unrecognized escape sequence \V..
At line:1 char:82
+ gwmi MSPower_DeviceWakeEnable -Namespace root\wmi | where {$_.instancename -m
atch <<<< $nic.PNPDeviceID }
+ CategoryInfo : InvalidOperation: (:) [], RuntimeException
+ FullyQualifiedErrorId : BadOperatorArgument
Bad argument to operator ‘-match’: parsing “PCI\VEN_8086&DEV_1050&SUBSYS_015710
28&REV_02\4&1C660DD6&0&40F0″ – Unrecognized escape sequence \V..
At line:1 char:82
+ gwmi MSPower_DeviceWakeEnable -Namespace root\wmi | where {$_.instancename -m
atch <<<< $nic.PNPDeviceID }
+ CategoryInfo : InvalidOperation: (:) [], RuntimeException
+ FullyQualifiedErrorId : BadOperatorArgument
Bad argument to operator ‘-match’: parsing “PCI\VEN_8086&DEV_1050&SUBSYS_015710
28&REV_02\4&1C660DD6&0&40F0″ – Unrecognized escape sequence \V..
At line:1 char:82
+ gwmi MSPower_DeviceWakeEnable -Namespace root\wmi | where {$_.instancename -m
atch <<<< $nic.PNPDeviceID }
+ CategoryInfo : InvalidOperation: (:) [], RuntimeException
+ FullyQualifiedErrorId : BadOperatorArgument
Bad argument to operator ‘-match’: parsing “PCI\VEN_8086&DEV_1050&SUBSYS_015710
28&REV_02\4&1C660DD6&0&40F0″ – Unrecognized escape sequence \V..
At line:1 char:82
+ gwmi MSPower_DeviceWakeEnable -Namespace root\wmi | where {$_.instancename -m
atch <<<< $nic.PNPDeviceID }
+ CategoryInfo : InvalidOperation: (:) [], RuntimeException
+ FullyQualifiedErrorId : BadOperatorArgument
The problem, it seems, is that the PNPDeviceID property contains characters that have a meaning in a regular expression. The PNPDeviceID is shown here:
PS C:\> $nic.pnpdeviceid
PCI\VEN_8086&DEV_1050&SUBSYS_01571028&REV_02\4&1C660DD6&0&40F0
The special characters need to be escaped before submitting to the Regex engine. This could be a tedious problem. But, then I remembered there is an escape method from the REGEX class. The Regex.Escape method is documented on MSDN and is easy to use. It will escape any invalid character in a string, and permit easy use of that string. This is exactly what is needed here. I place the call to the escape method just in front of the PNPDeviceID property. I store the returned object in a variable called $nicPower and I query the variable to ensure I contain the proper network adapter. Notice that the status of the enable property is set to false. The command and associated output are shown here:
PS C:\> $nicPower = gwmi MSPower_DeviceWakeEnable -Namespace root\wmi -cn dc1 -cred $cred | where {$_.instancename -match [regex]::escape($nic.PNPDeviceID) }
PS C:\> $nicPower
__GENUS : 2
__CLASS : MSPower_DeviceWakeEnable
__SUPERCLASS : MSPower
__DYNASTY : MSPower
__RELPATH : MSPower_DeviceWakeEnable.InstanceName=”PCI\\VEN_8086&DEV_105
0&SUBSYS_01571028&REV_02\\4&1c660dd6&0&40F0_0″
__PROPERTY_COUNT : 3
__DERIVATION : {MSPower}
__SERVER : DC1
__NAMESPACE : root\wmi
__PATH : \\DC1\root\wmi:MSPower_DeviceWakeEnable.InstanceName=”PCI\\V
EN_8086&DEV_1050&SUBSYS_01571028&REV_02\\4&1c660dd6&0&40F0_0
“
Active : True
Enable : False
InstanceName : PCI\VEN_8086&DEV_1050&SUBSYS_01571028&REV_02\4&1c660dd6&0&40
F0_0
Now, all I need to do is to change the value of the Enable property from False to True. After I have done that, I need to call the Put method from the base WMI object so that I write the changes back to the WMI database. These two commands and their associated output are shown here:
PS C:\> $nicPower.Enable = $true
PS C:\> $nicPower.psbase.Put()
Path : \\dc1\root\wmi:MSPower_DeviceWakeEnable.InstanceName=”PCI\\VEN_
8086&DEV_1050&SUBSYS_01571028&REV_02\\4&1c660dd6&0&40F0_0″
RelativePath : MSPower_DeviceWakeEnable.InstanceName=”PCI\\VEN_8086&DEV_1050&S
UBSYS_01571028&REV_02\\4&1c660dd6&0&40F0_0″
Server : dc1
NamespacePath : root\wmi
ClassName : MSPower_DeviceWakeEnable
IsClass : False
IsInstance : True
IsSingleton : False
It takes a reboot for the changes to take effect. Because I am working remotely and using WMI, I decide to use the Reboot method from the Win32_OperatingSystem WMI class. When calling the Reboot method from Win32_OperatingSystem, it seems to be a bit confusing. For example, if I use the [WMICLASS] type accelerator, the Reboot and Shutdown methods appear as shown here:
PS C:\> [wmiclass]”Win32_OperatingSystem”
NameSpace: ROOT\cimv2
Name Methods Properties
Win32_OperatingSystem {Reboot, Shutdown {BootDevice, BuildN…
But, when I attempt to use the Invoke-WmiMethod cmdlet to reboot the computer, an error occurs. The error is shown in the following figure.
Before I actually reboot the system, I connect via Remote Desktop and view the status of the network adapter. As shown in the following figure, it is not configured to allow the device to wake the computer.
Okay, I have verified the baseline configuration. Now I need to figure out why my reboot command did not work. The reason it failed is because the Reboot method is an instance method, not a static method. The easiest way to reboot the machine is to use the Get-WmiObject cmdlet, and call the method directly from the resulting object. This command and its associated output are shown here:
PS C:\> (gwmi win32_operatingsystem -CN dc1 -cred $cred).reboot()
__GENUS : 2
__CLASS : __PARAMETERS
__SUPERCLASS :
__DYNASTY : __PARAMETERS
__RELPATH :
__PROPERTY_COUNT : 1
__DERIVATION : {}
__SERVER :
__NAMESPACE :
__PATH :
ReturnValue : 0
After waiting an indeterminable amount of time, the remote domain controller is back up and running. I connect once again with Remote Desktop to see if my changes actually took. As shown in the following figure, it worked.
The complete sequence of commands could be placed easily in a single script and used to perform this configuration change in an automated fashion. Here are the commands:
EnableNicToWakeMachine.ps1
$cred = Get-Credential nwtraders\administrator
$nic= gwmi win32_networkadapter -filter “netenabled = ‘true'” -cn dc1 -cred $cred
$nicPower = gwmi MSPower_DeviceWakeEnable -Namespace root\wmi -cn dc1 -cred $cred |
where {$_.instancename -match [regex]::escape($nic.PNPDeviceID) }
$nicPower.Enable = $true
$nicPower.psbase.Put()
(gwmi win32_operatingsystem -CN dc1 -cred $cred).reboot()
TS, that is all there is to using WMI to set the ability of a NIC to wake up a computer. This also concludes WMI Method Week. Join us tomorrow when we have a guest blog article by Robert Robelo.
I invite you to follow me on Twitter and Facebook. If you have any questions, send email to me at scripter@microsoft.com, or post your questions on the Official Scripting Guys Forum. See you tomorrow. Until then, peace.
Ed Wilson, Microsoft Scripting Guy
This is good information, I am running powershell 5.1 and when I try to run the script I get a the errors stated below, any thoughts?
gwmi : Invalid query "select * from win32_networkadapter where netenabled = ‘true'"At line:2 char:7
The property 'Enable' cannot be found on this object. Verify that the property exists and can be set.At line:5 char:1
Method invocation failed because [System.Management.Automation.PSInternalMemberSet] does not contain a method named 'Put'.At line:6 char:1