views:

307

answers:

1

PowerShell Script Running as a Service Behaves Strangely

The Project: Create a background process that determines if the on board network card is connected. If it is connected, disable the wireless network card. When the onboard network card is not connected, re-enable the wireless card.

Why: Users hot-dock all the time, getting funky routing tables OR get bound to the wrong DNS servers. When they attempt to access a local resource, say printers, they aren’t able to and then are in my cube (they would file a ticket, but that too would be a local resource). Trying to convince users to disable their own wireless (via switch on laptop) or not hot dock has met with limited success.

The Problem: The PowerShell script below does run, and does work under my testing conditions. Likely under most testing conditions as the code and wmi queries are pretty generic. Running the script manually yields the expected results, HOWEVER running the script as a service via the only method I could find, srvany.exe, yielded unexpected results and “broke stuff”.

Details: Running the script as a service, via srvany.exe, works ONCE. When the loop comes back around to test the network connection or tries the method to enable or disable it. The errors indicate that “get-wmiobject” is not a proper Cmdlet. Huh? It works, manually, it works once, but a second time after it disabled the wireless network card it does not. Worse yet MY shell , outside of the service, suddenly can’t do a get-wmiobject, until…. until you go into Device Manager and re-enable the wireless network card yourself.

Debugging attempts: I rewrote the script and cleaned it up a little to allow for it to get the objects outside of the Do While loop. Nothing changed, but I left the script that way as it seems cleaner anyhow. I enabled “Interact with Desktop” in the service properties and sure enough you can see the script trying to work and getting the before mentioned errors. Please help. Again the object here is to run a background process, one with enough privileges in Vista or 7 to disable and enable the wireless network card.

#***********************************************************************
# "switch-wifi-srv.ps1"
# This script attempts  to identify if a wired network card is in use if
# one is, the Wireless network card is disabled, until the wired network
# card is no longer in use.
#
# Written by Aaron Wurthmann - aaron (AT) wurthmann (DOT) com
#
# 2010.02.10 ver 2 (Service Version)
# If you edit please keep my name or at the very least original author's.
# As of this writing I am unsure if script will work with all scenarios,
# however it has worked for me on Dell laptops running Windows 7 x64.
# -----------------------------------------------------------------------
# This script comes with ABSOLUTELY NO WARRANTY. 
# You may redistribute copies of the script under
# the terms of the GNU General Public License.
# -----------------------------------------------------------------------
# Service Installation:
# Aquire and install the Windows 2003 Resource Kit OR the srvany.exe.
# Use sc.exe and srvany.exe to create a service....
#   sc create SwitchWifiAuto binPath= "C:\Program Files (x86)\Windows Resource Kits\Tools\srvany.exe" DisplayName= "Switch Wifi Automatically"
# Edit registry entry for SwitchWifiAuto, add a key and a string value...
#   HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\services\SwitchWifiAuto\Parameters]
#   "Application"="C:\\Windows\\System32\\WindowsPowerShell\\v1.0\\powershell.exe -ExecutionPolicy RemoteSigned -File C:\\SwitchWifiAuto\\switch-wifi-srv.ps1"
#************************************************************************


$state=""
$wireStatus=""
$wifiStatus=""

# Get Wired and Wireless Card Objects
$objWire=get-wmiobject -class win32_networkadapter -namespace root\CIMV2 | Where-Object {$_.Name -notmatch "Wireless" -and $_.Name -notmatch "Virtual" -and $_.PhysicalAdapter -eq "True"} 
$objWifi=get-wmiobject -class win32_networkadapter -namespace root\CIMV2 | where-object {$_.Name -match "Wireless"}

# Get Name of Service to be Used in totally useless Do While Loop
$objService=get-service -display "Switch Wifi Automatically"

# Begin Do While Loop
Do {
#   Get status of wired network card. If enabled and connected set $state to Disable (which will later Disable the Wifi network card)
    [string]$wireStatus=$objWire | % {$_.NetEnabled}
    if($wireStatus -eq "True") {
        $state="Disable"
    }
#   Get Status of wireless card.
    if($objWifi){
        [string]$wifiStatus=$objWifi | % {$_.NetEnabled}
#       If $state is not set to disable and if the wireless card is currently disabled, enable it.
        if($state -ne "Disable") {
            if($wifiStatus -eq "False") {
                Out-Null -InputOject ($objWifi | % {$_.Enable()})
            }
#       If $state is set to Disable and if wireless card is currently enabled, disable it.
        } else {
            if($wifiStatus -eq "True") {
                Out-Null -InputOject ($objWifi | % {$_.Disable()})
            }
        }
    }

# Reset Checked Variables for good measure
$state=""
$wireStatus=""
$wifiStatus=""

# Sleep for 120 seconds (two minutes)
Start-Sleep -s 120

# Continuing looping (do while) until the service is not running.
# This is of course technically useless as when the service is not running neither is the script to check if the service is not running.
# I made it this way however because I don't like infinite loops and I thought it would be funny to it this way instead of while $var=0
} while ($objService.Status -eq "Running")
A: 

Try to remove any output. Service don't have stdout stream. And when the buffer is full strange thing happens. Just a guess ( I never used powershell ).

Igal Serban
That is a VERY good point. There is indeed output right now. When the method to disable or enable happens there is output. Hrmmmm
Aaron Wurthmann
Well that wasn't it though that did help and it gave me a reason to go fix and learn how to suppress output.Editing original post to reflect changes.
Aaron Wurthmann