I'm using the VirtualDesktop module in Windows Powershell. Trying to test whether a virtual desktop already exists, and if not add it. My code, however, always fails to identify whether the virtual desktop already exists.
$DesktopList = Get-DesktopList
# $DesktopList returns:
Number Name Visible
------ ---- -------
0 Desktop 1 False
1 Web True
2 Explore False
3 Mail False
4 MSO False
I've tried
If (-Not $DesktopList -Contains 'Web') # ---> returns False (should be True)
If ($DesktopList -Contains 'Web' -eq $FALSE) # ---> returns True (should be False)
I'm guessing this has something to do with the index vs name (i.e., "Web") being referenced, but I'm not clear how to fix.
Thank you.
It seems VirtualDesktop doesn't support the -name parameter (or at least I couldn't figure out how to make it work). Instead, I used the brute-force approach of first deleting all virtual desktops, then re-adding them one at a time, and (if not already running) launching applicable apps on each virtual desktop.
Related
I have to re-mount removable drives (which require authentication) each time I boot the computer and Windows Indexing keeps removing the removable drives (perhaps because the removable drives are not available when the computer boots). In an ideal world Windows Indexing would keep these locations and just list them as 'Unavailable' (which it sometimes does). However because it doesn't I am interested in executing a script that queries the Windows Indexing locations and if it does not list the removable drives then add them. At the bottom of this thread I pasted the Batch script that I setup to run at boot (via Start Up folder) to search for a specific folder that is available thereafter mounting one of the removable drives.
I have found several examples of how to do this on Windows 7 (links pasted below) but I can't figure out how to do it in Windows 10. The links provided to the DLL (Microsoft.Search.Interop.dll) no longer resolve.
When searching for the latest Windows Search SDK for Windows 10 I was lead to the Windows SDK here:
https://learn.microsoft.com/en-us/windows/win32/search/-search-developers-guide-entry-page
I installed the C++ related portion of the Windows SDK then searched for Microsoft.Search.Interop.dll but I couldn't find it. Perhaps the DLL has changed?
From How to rebuild Windows Search Index by using PowerShell?
Load DLL containing classes & interfaces
Add-Type -path "C:\Temp\SearchIndexSdk\Microsoft.Search.Interop.dll"
#Provides methods for controlling the Search service. This
interface manages settings and objects that affect the search engine
across catalogs.
https://msdn.microsoft.com/en-us/library/bb231485(v=vs.85).aspx
$sm = New-Object Microsoft.Search.Interop.CSearchManagerClass
#Retrieves a catalog by name and creates a new ISearchCatalogManager
object for that catalog.
$catalog = $sm.GetCatalog("SystemIndex")
#Resets the underlying catalog by rebuilding the databases and performing a full indexing.
#https://msdn.microsoft.com/en-us/library/bb266414(v=vs.85).aspx
$catalog.Reset()
From How to add a location to windows 7/8 search index using batch or vbscript?
#Code copied from "Powershell Tackles Windows Desktop Search" http://powertoe.wordpress.com/2010/05/17/powershell-tackles-windows-desktop-search/
#Microsoft.Search.Interop.dll is needed, download from http://www.microsoft.com/en-us/download/details.aspx?id=7388
#Load the dll
Add-Type -path "D:\Unattend\UserFiles\Tools\Microsoft.Search.Interop.dll"
#Create an instance of CSearchManagerClass
$sm = New-Object Microsoft.Search.Interop.CSearchManagerClass
#Next we connect to the SystemIndex catalog
$catalog = $sm.GetCatalog("SystemIndex")
#Get the interface to the scope rule manager
$crawlman = $catalog.GetCrawlScopeManager()
#add scope
$crawlman.AddUserScopeRule("file:///D:*",$true,$false,$null)
$crawlman.SaveAll()
I would add a comment to the existing threads but I am not able to because I don't have reputation of 50 (dumb rule IMO).
Last... I found this site which lists the DLL along with some code but it hasn't been updated in a long time.
https://github.com/FileMeta/WindowsSearchSample
Thanks in advance!
Batch script that runs at boot:
#echo off
echo Windows Search is being restarted to recognize the Z drive
:while
if EXIST Z:\Watch (
I WANT TO CALL POWERSHELL SCRIPT TO ADD THE LOCATION TO THE INDEX IF NEEDED HERE
sc stop WMPNetworkSvc
ping 127.0.0.1 -n 5 > nul
sc stop WSearch
ping 127.0.0.1 -n 5 > nul
sc start WSearch
ping 127.0.0.1 -n 5 > nul
sc start WMPNetworkSvc
echo Exiting this script in 5 seconds
ping 127.0.0.1 -n 5 > nul
exit
) else (
echo Waiting 60 seconds to check if Z drive is available
ping 127.0.0.1 -n 60 > nul
goto :while
)
When I do a search for Searchdll in what I believe to be the folder where the Windows SDK installed to (C:\Program Files (x86)\Windows Kits\10) I find the following. If I had to guess which DLL is the Windows 10 equivalent of Windows 7's Microsoft.Search.Interop.dll I would guess that it's the 1st one i.e. interop.searchapi.dll.
Add-Type -Path "C:\Program Files (x86)\Windows Kits\10\bin\10.0.19041.0\x64\interop.searchapi.dll" does return without error... however $sm = New-Object Microsoft.Search.Interop.CSearchManagerClass returns with error that it cannot find the class in the assembly.
When I cd to "C:\Program Files (x86)\Windows Kits\10\bin\10.0.19041.0\x64" and enter ([appdomain]::currentdomain.GetAssemblies() | Where-Object Location -Match 'interop.searchapi').gettypes() I get the following
When I enter (([appdomain]::currentdomain.GetAssemblies() | Where-Object location -match 'interop.searchapi.dll').gettypes() | Where-Object name -eq 'CSearchManagerClass').getmembers() | Format-Table name, membertype I get
From the list of commands in the previous threads I do see GetCatalog and I presume that the members GetCrawlScopeManager, AddUserScopeRule, Reset, and SaveAll exist.
I don't know how to find the fully qualified class name or I'm doing something else wrong (unknowingly).
When I enter ([appdomain]::currentdomain.GetAssemblies() | Where-Object Location -Match 'interop.searchapi').fullname I get the following
Interop.SearchAPI, Version=10.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35
But when I enter $sm = New-Object Interop.SearchAPI.CSearchManagerClass I get an error that it can't find the type Interop.SearchAPI.CSearchManagerClass.
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}}
}
}
On all the Windows 10 computers I re-image, I want to disable the option in Sound for giving exclusive control to each device to applications. I have located the registry keys and values:
HKLM\Software\Microsoft\Windows\CurrentVersion\MMDevices\Audio\Capture\RANDOM_STRING\Properties
HKLM\Software\Microsoft\Windows\CurrentVersion\MMDevices\Audio\Render\RANDOM_STRING\Properties
Within each of these keys (1st one is for Mics and 2nd is for Speakers) their are the two DWORD-32 values in each:
{b3f8fa53-0004-438e-9003-51a46e139bfc},3
{b3f8fa53-0004-438e-9003-51a46e139bfc},4
I want to basically make a batch script that will find these two values and set them to 0 for each audio devices. I'll have it run via Task Scheduler or something to make sure it gets new devices too.
The problem for me is that RANDOM_STRING portion of each path. Each one is ~25 random characters; it looks similar to the value names with the ,# at the end. I know how to change a value via a specific path, but here their is that randomized key name, and then new ones as new devices are plugged in.
Is their any way for me to create a batch file (or VBS/PowerShell) that will search the registry (or just Audio to narrow it down quicker) for those two values, and change their values to 0? Or if any other ways of going about this if so?
An example of the process I'd like (or again, something else similar):
Search for the DWORD-32 value "{b3f8fa53-0004-438e-9003-51a46e139bfc},3" within
the path
"HKLM\Software\Microsoft\Windows\CurrentVersion\MMDevices\Audio\"
and all the sub-keys within.
Set the value of the DWORD-32 value
"{b3f8fa53-0004-438e-9003-51a46e139bfc},3" to 0.
Search for the DWORD-32 value "{b3f8fa53-0004-438e-9003-51a46e139bfc},4" within
the path
"HKLM\Software\Microsoft\Windows\CurrentVersion\MMDevices\Audio\"
and all the sub-keys within.
Set the value of the DWORD-32 value
"{b3f8fa53-0004-438e-9003-51a46e139bfc},4" to 0.
I hope you know what are you doing. Manipulating registry is very risky. If you are absolutely sure, take a look at this script:
ls 'HKLM:\Software\Microsoft\Windows\CurrentVersion\MMDevices\Audio\Capture\*\Properties\' | `
where {$_.Property -contains '{b3f8fa53-0004-438e-9003-51a46e139bfc},3'} | `
Get-ItemProperty -Name '{b3f8fa53-0004-438e-9003-51a46e139bfc},3'
#Set-ItemProperty -Name '{b3f8fa53-0004-438e-9003-51a46e139bfc},3' -Value 0
Make sure this script (with Get-ItemProperty) gets only desired keys. To change values, replace last line with commented one. Make sure you have proper permissions. And finally: do it at you own risk :)
I was unable to get the other answer working. I am trying to ban the Netflix app from being unbearably loud (which it does if it gets exclusive control of the sound device) every time I reinstall the geforce drivers (when the exclusive control resets).
So:
Get-ChildItem -recurse -path 'HKLM:\SOFTWARE\Microsoft\Windows\CurrentVersion\MMDevices\Audio\Render\'| `
Foreach-Object { if ($_.Property -eq '{b3f8fa53-0004-438e-9003-51a46e139bfc},3') {$_|Get-ItemProperty -Name '{b3f8fa53-0004-438e-9003-51a46e139bfc},3'} }`
Gives me this output:
{b3f8fa53-0004-438e-9003-51a46e139bfc},3 : 0
PSPath : Microsoft.PowerShell.Core\Registry::HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\
Windows\CurrentVersion\MMDevices\Audio\Render\{94743724-8af1-4abc-8d45-275
7184ec5f2}\Properties
PSParentPath : Microsoft.PowerShell.Core\Registry::HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\
Windows\CurrentVersion\MMDevices\Audio\Render\{94743724-8af1-4abc-8d45-275
7184ec5f2}
PSChildName : Properties
PSProvider : Microsoft.PowerShell.Core\Registry
{b3f8fa53-0004-438e-9003-51a46e139bfc},3 : 0
PSPath : Microsoft.PowerShell.Core\Registry::HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\
Windows\CurrentVersion\MMDevices\Audio\Render\{b4ed07ae-0ee7-4ffb-8370-8bb
08a59a941}\Properties
PSParentPath : Microsoft.PowerShell.Core\Registry::HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\
Windows\CurrentVersion\MMDevices\Audio\Render\{b4ed07ae-0ee7-4ffb-8370-8bb
08a59a941}
PSChildName : Properties
PSProvider : Microsoft.PowerShell.Core\Registry
This looks good.
To write it the Get-ItemProperty needs to change to Set-ItemProperty but it results in a security error, please consult https://stackoverflow.com/a/35844259/308851 to take ownership of the relevant key.
I'm trying to add a launch condition to my .msi package deployment but it's not working. I want to check if UAC is enabled in the target machine. My values for the registry search are:
Property: UACSTATUS
RegKey: SOFTWARE\Microsoft\Windows\CurrentVersion\Policies\System
Root: vsdrrHKLM
Value: EnableLUA
The value is of a REG_DWORD type. 1 for enabled, 0 for disabled.
Then I created the launch condition:
(Name): UACVerification
Condition: UACSTATUS = 0
InstallUrl: <left blank for now>
Message: You must disable UAC prior to install this application.
The problem is: it doesn't work. Testing in my machine (which has UAC disabled), both comparisons for 0 or 1 in the Condition returns false and doesn't allow me to continue with the installation.
Aren't REG_DWORD types treated as numbers? I tried using quotes ("0", or '0') but it does not work as well.
I would check the HKEY setting. Make sure that you are checking for the HKEY_CURRENT_USER? (or HKEY_LOCAL_MACHINE). I have run into a similar issue in the past, and if my memory is working properly, then this solved it for me.
Oh, and if this proves to be correct, then I believe the reason you are getting false is because on some of these branches, the System or UACSTATUS does not exist.
REG_DWORD types are treated as boolean.
0 = false
1 = true
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.