PowerShell Script Running as a Service Behaves Strangely - windows

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")

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 ).

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.
You need to include these within the loop or you will not get updated values and the loop will do nothing.

Related

Preserve Active Directory trust relationships securely in AWS between VM's that start and stop

Developing Active Directory for a scalable and hackable student environment and I cannot manage to preserve the Domain Trust Relationship after the VM's restart. On first launch everything works, but after stopping/starting the AD Set, the trust relationship is broken.
Configuration Basics.
Three machines built and running in AWS (Windows Server 2012)
Domain Controller (Pre-Built Forest, Domains, Users, Computers, GPO's, etc)
Two "Targets" with varying permissions.
AMIs are built and domian joined before imaging.
Prior to imaging, Target Boxes are REMOVED from the domain, leaving a single DC and two un-joined Windows Server 2012 boxes.
Boxes are stopped without SysPrep to preserve SIDs and other variables like admin passwords, and an image is taken. User data is enabled
At this point, I can relaunch these boxes from AMI, re-join the domain, and I have no issues after restarting.
Here are the next steps.
The AMI's are run through a code pipeline that applies user data to the boxes to Domain Join and set the DNS to the IP of the DC.
Code exists to prevent the targets from crating until the DC is listening so they can join the domain.
On creation, things work flawlessly again.
After stopping and restarting, however, I start getting "NO_LOGON_SERVER" errors with tools, and cannot login with a domain user.
There are obvious solutions, but nearly all of them manual, and this must be automated. Furthermore, I must configure this in a way that no passwords are exposed on the box or retained as tickets or hashes in lsass that could ruin the exploint path.
If it helps, here is the User-Data that domain joins the targets.
<powershell>
# Checking for response from DC
do {
Start-Sleep 30
} until(Test-NetConnection -InformationLevel Quiet '{DC_IP_ADDR}')
# "true" if Domain Joined
$dCheck = (Get-WmiObject -Class Win32_ComputerSystem).PartOfDomain
# Join domain if not already, skip if joined.
if ($dCheck -eq 'True') {
echo "I was domain joined after restarting." >> C:\Windows\Temp\log.txt
}
else {
# Allows 'rdesktop' by disabling NLA as a requirement
Set-ItemProperty 'HKLM:\SYSTEM\CurrentControlSet\Control\Terminal Server\' -Name "fDenyTSConnections" -Value 0
# Set DNS to DC IP address via custom variable
$adapterIndex = Get-NetAdapter | % { Process { If ( $_.Status -eq "up" ) { $_.ifIndex } }}
Set-DNSClientServerAddress –interfaceIndex $adapterIndex –ServerAddresses ('{DC_IP_ADDR}','8.8.8.8')
#Set DA Credential object and join domain
$username = 'MYDOMAIN\ADMINISTRATOR'; $password = ConvertTo-SecureString -AsPlainText 'NotTheActualPasswordButReallySecure' -Force; $Credentials = New-Object System.Management.Automation.PSCredential $Username,$Password
Add-Computer -Domain 'MYDOMAIN.LOCAL' -Credential $Credentials -Force -Restart
}
</powershell>
<persist>true</persist>
And here is the Domain Controller. It is scheduled to change it's DA Password after 4 minutes so that the password exposed in the user data above is no longer valid
<powershell>
# Enable Network Discovery
netsh advfirewall firewall set rule group="Network Discovery" new enable=Yes
# Allows 'rdesktop' by disabling NLA as a requirement
Set-ItemProperty 'HKLM:\SYSTEM\CurrentControlSet\Control\Terminal Server\' -Name "fDenyTSConnections" -Value 0
Start-Sleep -Seconds 240
# Recycle DA Password
powershell.exe -C "C:\Windows\Temp\recycle.ps1"
echo "Done" > "C:\Users\Administrator\Desktop\done.txt"
</powershell>

Trying to back up my Bitlocker Key to ADDS Through Script

I'm trying to automatize the process of storing BitLocker Keys to ADDS.
I wanna be able to run the following script at logon, in order to do that, as the OS is deployed through WDS which already encrypts the drive:
$BitVolume = Get-BitLockerVolume -MountPoint $env:SystemDrive
$RecoveryKey = $BitVolume.KeyProtector | Where-Object { $_.KeyProtectorType -eq 'RecoveryPassword' }
Backup-BitLockerKeyProtector -MountPoint $env:SystemDrive -KeyProtectorId $RecoveryKey.KeyProtectorID
BackupToAAD-BitLockerKeyProtector -MountPoint $env:SystemDrive -KeyProtectorId $RecoveryKey.KeyProtectorID
I always get access denied as this has to run as admin...
Is there any command I can use prior the code to run it as admin?
I've googled but I found no useful info to actually do this...
As for the access denied part... as was already sated, you need to start your PowerShell session as an admin. However, as a point of note about your code, you are only targeting the system/os volume... which may not be the only volume that's encrypted. If you want to programmatically backup all of the encrypted volumes, may I suggest one of the two following options...
One-liner:
Get-BitLockerVolume | where {$_.VolumeStatus -like "FullyEncrypted"} | foreach {foreach($Key in $_.KeyProtector){if($Key -like "RecoveryPassword"){Backup-BitLockerKeyProtector -MountPoint $_.mountpoint -KeyProtectorId $key.KeyProtectorId}}}
Or, if you prefer something a little bit easier to read...
Script Block:
foreach ($BLV in Get-BitLockerVolume){
if ($BLV.VolumeStatus -like "FullyEncrypted"){
foreach ($Key in $BLV.KeyProtector) {
if ($Key -like "RecoveryPassword") {
Backup-BitLockerKeyProtector -MountPoint $BLV.MountPoint -KeyProtectorId $Key.KeyProtectorId
}#if
}#foreach
}#if
}#foreach
Neither is super eloquent... but, with this method it will grab all of the encrypted volumes on the system and add them to AD. You would need to modify the code slightly to add the AAD backup option you cited of course.
P.S. I'm only responding because I recently had to solve this problem of multi-volume backups as a one-liner solution and figured I would share it since your post was a top search result when I looked for a pre-canned solution. Cheers! :)

List Last Windows Password Change For All Users On A Non-Domain System

I have found an answer to this question for systems that are attached to an AD domain controller. However, this question is for standalone systems where there is no possibility of attaching to a domain controller. Essentially, air-gapped systems.
Short and sweet: Is there a way to list the last time each user changed their Windows password for a non-domain, air-gapped system (either Windows 7 or 10) all at once either as a batch file or PowerShell script?
I know that net user {username} | find /I "Password last set" will do it for them one at a time. However, that would be tedious to run multiple times per machine and we have over 60 systems of this type. So I'm looking for a way to do this in one fell swoop, if possible.
As a caveat, we don't have the option of installing the activedirectory module in PowerShell for this. Also, since the majority of the systems are Windows 7, we don't have access to the Bash command line tools that would be available in Windows 10.
Any and all help with regard to this is appreciated.
Here's one way using the ADSI WinNT provider:
$computerName = [Net.Dns]::GetHostName() # i.e., local computer
$computer = [ADSI] "WinNT://$computerName,Computer"
$childObjects = $computer.Children
foreach ( $childObject in $childObjects ) {
if ( $childObject.Class -eq "User" ) {
if ( $childObject.PasswordAge[0] -gt 0 ) {
$pwdLastSet = (Get-Date).AddSeconds(-$childObject.PasswordAge[0])
}
else {
$pwdLastSet = $null
}
$childObject | Select-Object `
#{Name="AdsPath"; Expression={$_.AdsPath}},
#{Name="PasswordLastSet"; Expression={$pwdLastSet}}
}
}

Powershell Win32_ServerConnection on TS Server 2012 no result

I'm trying to execute a simple command on one of a TS part of a RDS farm and I get no result. I just want to see every connection on the TS using:
Get-WmiObject Win32_ServerConnection -ComputerName MYTSSERVER
and I get no result at all. Any idea what could be the cause?
Thank you
Win32_ServerConnection shows active connections to network shares on the machine. If you do not have active network shares or connections to them there will be no results.
I assume since they're terminal servers in an RDS farm that you're looking for remote sessions in which case you want Win32_LoggedOnUser. That said, Win32_LoggedOnUser doesn't clear sessions that have been disconnected or even closed. It shows all sessions since the last computer reboot whether that information is still valid or not.
It's incredibly annoying but the best way to list real and active sessions is to list all copies of explorer.exe running on the machine and who they belong to or use the cmd application query.exe. There are ways in PowerShell to turn the output of query.exe into objects:
$Users = query user /server:TERMSERV01 2>&1
$Users = $Users | ForEach-Object { (($_.trim() -replace ">" -replace "(?m)^([A-Za-z0-9]{3,})\s+(\d{1,2}\s+\w+)", '$1 none $2' -replace "\s{2,}", "," -replace "none", $null)) } | ConvertFrom-Csv
$Users

windows get IP dynamically

i want to implement the following logic. Does it possible to have such implementation using batch or power shell ? please share with me script for that.
Let say I have a configuration file with the following "config.propertis":
BOOTPRORO=statis or dhcp
IPADDR=192.168.10.10
NETMASK=255.255.255.0
GATEWAY=192.168.10.1
DNS=8.8.8.8
I want that at startup the system will check that file and configure network accordingly:
OS: Windows
if in BOOTPROTO=dhcp, when use DHCP in network configuration and ignore all another in config file, except DNS
if in BOOTPROTO=static, then use all variables from config file to configure IP as static.
So, I have such logic under the Linus, using shell. The script in configured in rc.d and execute before network service. Does it possible to implement such over the Windows ? Guys, please share the script !
We can definitely do this.
First things first, because a lot of systems have more than one network interface, you'll need to determine what the ifIndex is of the adapter that we want to change. Do that by running Get-NetIPInterface. You should see results like this:
In my example and going forward, I'll be using this index, 41. You should change this to match what you find on your own computer.
OK, now to read from the text file. Since you've provided the data in a key=value pair format, commonly called a hashtable, we can easily grab the data from there using ConvertFrom-Stringdata. This will give us a PowerShell hashtable, and we can pull the needed line out like this.
$values = get-content T:\config.properties | ConvertFrom-StringData
$values.BootProro
>statis
We can us this to set the PC in Dynamic IP mode, or to set static addresses. Now, for you to use this in your environment, you need to find the ifIndex, as I mentioned before. replace my index of 41 with your own, and then give it a shot. I've added -WhatIf to every line, so you will see what would happen when you run it. If you're happy with the changes it woudl make, remove -Whatif to make the script actually change the settings.
$values = gc T:\config.properties | ConvertFrom-StringData
if ($values.BOOTPRORO -eq "dhcp"){
Write-Output "---DHCP mode detected in 'config.properties' file"
Write-Output "---Setting Set-NetAdapter -DHCP Enabled"
Set-NetIPInterface –InterfaceIndex 41 –Dhcp Enabled -WhatIf
}
else{
Write-outPut "---static mode detected in 'config.properties' file"
Write-Output "---Removing network configuration"
Remove-NetIPAddress -InterfaceIndex 41 -whatif
Write-Output "---Setting new network configuration equal to"
$values
New-NetIPAddress -DefaultGateway $values.GATEWAY -IPAddress $values.IPADDR -PrefixLength 24 -InterfaceIndex 41 -WhatIf
Set-DnsClientServerAddress -ServerAddresses $values.DNS -InterfaceIndex 41 -WhatIf
}
The output looks like this:
in Windows we can set ip address via batch file or powershell script but when you use dhcp address your ip is Dynamic not static I Imposition you want static ip address
BAtch-file
netsh interface ip set address name=”Local Area Connection” static 192.168.10.10 255.255.255.0 192.168.10.1
netsh interface ip set dns name=”Local Area Connection” static 8.8.8.8
if you want be dhcp You should set
netsh interface ip set address name=”Local Area Connection” source=dhcp
note I Imposition you nic name is Local Area Connection
In powershell V3.0 and Later we Used
New-NetIPAddress –InterfaceAlias “Local Area Connection ” –IPv4Address “192.168.10.10” –PrefixLength 24 -DefaultGateway 192.168.10.1
Set-DnsClientServerAddress -InterfaceAlias “Local Area Connection” -ServerAddresses 8.8.8.8
and for startup you can put script .bat and .ps1 in startup windows but attention you should Set-ExecutionPolicy bypass before U run any script of powershell
for startup any script see link

Resources