VSCode - Powershell - Network Drives - powershell

I have started using VSCODE for editing and running scripts.
If I run VSCODE as admin, I cannot access files on a network drive (mapped or otherwise).
If I don't run VSCODE as admin I cannot execute the PS scripts I need to.
Has anyone experienced something similar, or found a work around?

Since the Administrator account doesn't have the drive mappings your user account has, you can try accessing the Universal Naming Convention (UNC) path to the network resources/shares directly.
Format
\\<server-hostname-or-IP>\<share-name>\<directory-name>
Examples
\\server1\c$
\\server2\share\foo\bar
If you don't know the UNC paths for the mapped drives, run net use from a cmd.exe prompt under your user (not admin) account context. The UNC paths fall under the Remote column heading in the output, and should resemble the format outlined above.
Helpful Links
UNC paths
Net use

Related

Export PowerShell prompt to remote session

I want to customize my PowerShell prompt to my personal preference. After following the information provided by the Microsoft docs I finally ended up with a satisfying result.
Then I opened a remote session and the prompt was not loaded during the remote session. Instead the default one was used.
My question now is whether there's a possability of exporting the local prompt to a PowerShell remote session (to every computer). What's interesting in my opinion is that the remote session to my own computer also didn't load the globally configured prompt on my computer. Also I want to know whether (and how) you can customize this remote prompt if there's a special possability (e.g. define a function like remote-prompt {...} to configure the PSRemoting prompt) for this, provided that you do need (or can) export the local prompt.
The official docs to customize the prompt only explained local things like nesting which are not working by default.
You might want to do something with PowerShell Profiles.
Also you can change the look and feel from your PowerShell by changing the $host.UI.RawUI parameters. Eg. $host.ui.RawUI.WindowTitle = "Installing some stuff...", $host.ui.RawUI.WindowSize=(New-Object System.Management.Automation.Host.Size(1024,768), $host.ui.RawUI.ForeGroundColor = "red", etc...

Why is my file retrieved from FTP in a remote PowerShell session encrypted?

Yet another works-fine-locally-but-looses-its-mind-in-a-remote-session problem.
I have a PS script that runs standard Windows command line ftp.exe to get a file. Works a treat when ran directly, however when ran remotely via Invoke-Command it suddenly leaves the files with the encrypted bit set.
If I then, in the same PS session (in the same script), run cipher /d on the file, I get Access Denied. However if I log onto the remote machine using the same account, I can decrypt it.
So, question the first, is this a "feature" of ftp.exe? I can't find anything suggesting as such, but no other method of creating a file seems to result in it being encrypted, so I'm left thinking it is an intentional act by the application, like it checks the logon type and encrypts if it a network logon.
Second, why can I not immediately decrypt it? Same account, same session.
The essential bits of the script in question:
#the ftp script is just open, user, binary, get, quit
& ftp -n -v -s:"$script"
& cipher /d "$file_path"
I realize this is probably a pretty obscure edge case, but I'll leave an answer just in case anyone runs into anything similar.
As usual, ProcMon has all the answers...
At my company %HOMESHARE% is set to a network file server (by some GPO I believe).
As ftp.exe is retrieving a file, it writes to a temp file and then once finished, copies it over to the specified location. Even after knowing this, one might expect %TEMP% to be used for such a purpose, but no.
I'm not quite sure exactly how ftp.exe goes about determining the temp file location, but when I'm in a PSsession, it chooses my Documents folder (%USERPROFILE% I suppose), but when I'm in an RDP session it uses %HOMEPATH%. So of course my Documents folder is set to encrypt new files and so the temp file is encrypted and gets copied over, but the file share is not so it copies over clean.
Also, while I have found nothing official stating this, it does seem that cipher.exe is completely ineffective for a network logon. If after entering a PSSession I create a new file with Set-Content and attempt to encrypt using cipher /e <file> it gives the same access denied. Same account over RDP encrypts no problem;

Is there any way to persist VS Code extensions in VDI?

Every day when I log into VDI my vscode extensions get removed on a daily basis.
So I need to install them every day. Is there any walk around to keep the extensions with persistence and that I don't have to download/install it again on a daily basis when ever I log in.
Any help would be much appreciated and thanks in advance.
It seems that you are using a nonpersistent VDI, so you should ask your IT to install the vscode extensions that you need in the image stored in the servers.
Excerpt retrieved here:
There are two main approaches to VDI: persistent and nonpersistent. Persistent VDI provides each user with his or her own desktop image, which can be customized and saved for future use, much like a traditional physical desktop. Nonpersistent VDI provides a pool of uniform desktops that users can access when needed. Nonpersistent desktops revert to their original state each time the user logs out.
Found this on GitHub and it is down near the bottom... https://github.com/microsoft/vscode/issues/17691
Create an environment variable named VSCODE_EXTENSIONS. Set the path you wish the extensions to be stored. We used a network share in our implementation to keep extensions persistent in a non-persistent VDI. (e.g VSCODE_EXTENSIONS = \\Server\Share\%USERNAME%\.vscode)
This environment variable must be in place before VSCode launches. We are utilizing this with VSCode 1.52.1 and it is working for us.
This is how I got it to work in my environment. You need to install the extensions using the .vis format, and then copy the extensions from that local profile to a location any user can access. After that, create a GPO that will run this script at every logon and set the scope to your VDI access AD group. The logon GPO is located at User Configuration > Policies > Windows Settings > Scripts > Logon > Powershell This may be a crude way of doing it, but it's working in my environment.
#This will not work unless there are extensions on the root of the default user
#folder. Install Visual Studio Code and its extensions first, then copy the
#entire "\.vscode" folder from the user profile you installed it into and onto
#the default user profile root folder.
#This script tests to see if the extensions already exist in the root folder of
#the user logging in using the path described in the below variable.
$vscodeextensions = "$env:USERPROFILE\.vscode\extensions\ms-vscode.cpptools-
1.13.2"
#This will just allow the script to run.
Set-ExecutionPolicy bypass
If(-not(Test-Path $vscodeextensions)){
Copy-Item -Path "C:\Users\Default\.vscode\" -Destination "$env:USERPROFILE\"
-Force -Recurse
}
else{
Write-Host "Extensions already copied"
}

PowerShell: Start-Process Firefox, how do he know the path?

When I call the following code:
Start-Process Firefox
Then the PowerShell opens the browser. I can do that with several other programs and it works. My question is: How does the PowerShell know which program to open if I type Firefox? I mean, Im not using a concrete Path or something ...
I though it has something to do with the environment variables ... But I cannot find any variable there which is called Firefox ... How can he know?
I traced two halves of it, but I can't make them meet in the middle.
Process Monitor shows it checks the PATHs, and eventually checks HKLM\Software\Microsoft\Windows\CurrentVersion\App Paths\firefox.exe so that's my answer to how it finds the install location, and then runs it.
That registry key is for Application Registration which says:
When the ShellExecuteEx function is called with the name of an executable file in its lpFile parameter, there are several places where the function looks for the file. We recommend registering your application in the App Paths registry subkey.
The file is sought in the following locations:
The current working directory.
The Windows directory only (no subdirectories are searched).
The Windows\System32 directory.
Directories listed in the PATH environment variable.
Recommended: HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows\CurrentVersion\App Paths
That implies PowerShell calls the Windows ShellExecuteEx function, which finds FireFox as a registered application, or it tries the same kind of searching itself internally.
Going the other way to try and confirm that, the Start-Process cmdlet has a parameter set called UseShellExecute. The 'Notes' of that help says:
This cmdlet is implemented by using the Start method of the System.Diagnostics.Process class. For more information about this method, see Process.Start Method
Trying to trace through the source code on GitHub:
Here is the PowerShell source code for Start-Process.
Here, at this line it tries to look up the $FilePath parameter with CommandDiscovery.LookupCommandInfo.
Here it checks else if (ParameterSetName.Equals("UseShellExecute"))
Then Here is the .Start() function which either starts it with ShellExecute or Process.Start()
OK, not sure if ShellExecute and ShellExecuteEx behave the same, but it could be PS calling Windows, which is doing the search for "FireFox".
That CommandSearcher.LookupCommandInfo comes in here and follows to TryNormalSearch() which is implemented here and immediately starts a CommandSearcher which has a state machine for the things it will search
SearchState.SearchingAliases
Functions
CmdLets
SearchingBuiltinScripts
StartSearchingForExternalCommands
PowerShellPathResolution
QualifiedFileSystemPath
and there I get lost. I can't follow it any further right now.
Either it shortcuts straight to Windows doing the lookup
Or the PowerShell CommandSearcher does the same search somehow
Or the PowerShell CommandSearcher in some way runs out of searching, and the whole thing falls back to asking Windows search.
The fact that Process Monitor only logs one query in each PATH folder for "firefox.*" and then goes to the registry key suggests it's not doing this one, or I'd expect many more lookups.
The fact that it logs one query for "get-firefox.*" in each PATH folder suggests it is PowerShell's command searcher doing the lookup and not Windows.
Hmm.
Using Process Monitor I was able to trace the PowerShell.
It first searches the $env:path variable, then the $profile variable.
In my case firefox wasn't found and then it searches through a whole lot in the Registry and somehow finds it.
It might have something to do with how firefox is installed on the system.

Run Executable File Without UAC Popup as Administrator

I am running a large study where we have staff in various countries collecting information on tablet computers running Windows 10 Enterprise. Each staff member is assigned to a tablet and they log into the tablet with their standard username and password. These users do not have local admin rights on the machines, but all tablets have a single Administrator Username and Password which I know and these are uniform across the tablets.
Each night, users invoke a program on their tablets that uploads data to our servers and then we pass information back to the tablet during this synchronization process. Otherwise, they are disconnected from the internet. At the end of the synchronization process a program is executed that allows me to run any script I like, but the script executes under the standard user account (i.e. without elevated privileges).
I need to update all the tablets with a bug fix for software that they use on the tablets and I'd like to do this during the synchronization process. The bug fix is contained in a simple executable file that can be easily pushed to the staff memebers' tablets along with any code I like during the sync. If users were running the synchronization program as administrators, this wouldn't a problem as I could simply run the executable via a script at the end of the synchronization. But they aren't, so I'm trying to find a way that I could run a script (I don't really care what it is. It could be a windows batch file, a vbs script, VB.NET, powershell, etc.) and have that script execute with administrative privileges and run the installation without the UAC prompt interfering.
I don't even mind supplying the admin password in plaintext to be honest, since these users are all our employees and they can't really do anything really concerning to us with it (and I could always deploy a subsequent file through the synchronization process to delete the program that has the password in it). I realize this sounds somewhat complicated, but in a nutshell, I'd like to carry out these steps:
Send the bug update executable to the tablet computer (I can do this now)
Develop custom code, that will pass admin credentials to the tablet and install the executable in 1 without having the UAC appear (I can send the script to the tablet during sync but do not know how to execute it as the Admin without getting the UAC prompt).
Any ideas how I can do this? I've explored this all day with minimal success using PowerShell scripts like the ones described here and here. This was the closest I got after storing the credentials in $cred, but it continued to give me the UAC prompt:
Start-Process PowerShell.exe -Cred $cred -ArgumentList '-command &{Start-Process -FilePath C:\MySyncPath\BugFix32.exe -Verb runas}]
UPDATE
After some additional work, I think I'd be able to get this to run if I could somehow disable to UAC control with a script that can run under the regular user's account and pass the admin credentials to it. Any idea how I might be able to accomplish this? If I could get this to work, even with a reboot, I'd be able to accomplish what I need.
The actual issue you're having is that you want to update your application, but the application is in the Program Files folder (or some other location that standard users are not allowed to modify).
In order to allow any user the ability to update your program, you must grant all users Full Control to your folder. Ideally your application's installer would have done this adjustment to the DACL during installation (when the installer was running as an administrator).
For now you will have to settle for a final one-time requirement that the users elevate to administrator. Then you can disable all security on your application - allowing any user (malicious or not) to modify your application at will.
GrantEveryoneFullControlToFileOrFolder("C:\Program Files\Contoso");
with a pseudocode implementation of:
void GrantAllUsersFullControlToFileOrFolder(String path)
{
PACL oldDACL;
PACL newDACL;
PSECURITY_DESCRIPTOR sd;
//Get the current DALC (Discretionary Access Control List) and Security Descriptor
GetNamedSecurityInfo(path, SE_FILE_OBJECT, DACL_SECURITY_INFORMATION,
nil, nil, ref oldDACL, nil, ref sd);
//Create an SID for the "Users" group
PSID usersSid = StringToSid("S-1-5-32-545");
// Initialize an EXPLICIT_ACCESS structure for the new Access Control Entry (ACE)
EXPLICIT_ACCESS ea;
ZeroMemory(#ea, SizeOf(EXPLICIT_ACCESS));
ea.grfAccessPermissions = GENERIC_ALL;
ea.grfAccessMode = GENERIC_READ | GENERIC_WRITE | GENERIC_EXECUTE;
ea.grfInheritance = SUB_CONTAINERS_AND_OBJECTS_INHERIT;
ea.Trustee.TrusteeForm = TRUSTEE_IS_SID;
ea.Trustee.TrusteeType = TRUSTEE_IS_GROUP;
ea.Trustee.ptstrName = PChar(usersSID);
// Create a new ACL that merges the new ACE into the existing ACL.
// SetEntriesInAcl takes care of adding the ACE in the correct order in the list
SetEntriesInAcl(1, #ea, oldDACL, ref newDACL); //use LocalFree to free returned newDACL
//Attach the new ACL as the object's new DACL
SetNamedSecurityInfo(path, SE_FILE_OBJECT, DACL_SECURITY_INFORMATION,
nil, nil, newDACL, nil);
LocalFree(HLOCAL(sd));
LocalFree(HLOCAL(newDACL));
FreeSid(usersSID);
}
It's not completely unheard of for applications to be modifiable by any user: Most MMOs install updates while you play. MMOs usually have a shim applied by Microsoft that gives all users control of the application folder.
run the script as a domain admin account... and set execution policy before the script is run, then run as administrator... some applications are picky about UAC still, but Set-ExecutionPolicy [bypass/remotesigned] will ensure that you're not prompted. however, sharing and permissions may still be an issue if the domain admin account doesn't have access to the share. psexec does this, but it's literally a matter of doing what i just mentioned and the psexec file essentially writes out the permissions by the end of the script. the intent was to make sure that passwords weren't written in clear text, it hashes the password value. either way, if you want this done securely, using a GPO and making sure your file permissions/share is at the highest level might iterate out the prompt. that's why you'll see some batch files use %1 %2 %3 %4 %5 %6 %7 %8 %9 .... that's because it's automatically requesting elevation and will loop in an iterative cycle until the UAC prompt isn't necessary.
i know i'm bumping an old thread, but this is what i've found, trying to mix and match legacy cmd batches with powershell ... lots to consider about the execution policy leading into the call vs during the call...
This question is in the category of "when people ask for security holes as features".
You cannot bypass (or, if you prefer this phrasing, "programmatically accept") the UAC prompt and automatically elevate without interactive confirmation. UAC is designed specifically to prevent this. (If this were possible, all malware would do it.)
This isn't a PowerShell thing but a general windows 10 thing. You'd need to disable UAC for this. No experience with it on Windows 10 yet though.
You can try setting the EnableLUA registry key to 0. The key can be found in:
HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows\CurrentVersion\Policies\System
This will probably need a reboot to be active though.