Powershell Suppress Certificate Notification - powershell

I am writing a script to connect from a Windows 10 Client to a Terminal Server with the RDP-Protocoll.
The thought behind is: On these ThinClients we have about 20 RDP-Files. With about 10 of them, the password needs to be safed.
So it is quite a lot of work if you always have to save the password on every new ThinClient.
But I thought I could solve this problem with a powershell script. I just have to open the connection 1 time successfully and save the credentials and further on the credentials are saved.
I will show my code first:
$Server = "xx.yy.zz.xx"
$User = "DOMAIN\User"
$password = "password"
cmdkey /generic:"$Server" /user:"$User" /pass:"$password"
mstsc /v:"$Server"
This works so far.
But I always get the this Notification:
This is a Symbol-Picture from the Internet, as my Notification is in German. It is exactly the same, just easier to understand.
Even if I install the certificate, the notification keeps popping up.
How can I check the field with Powershell, where it says Don't ask me again for connections to this computer?

Ok i found a solution!
There is a registry-Key generated when you Tick "Dont ask me again..."
Now i just added the necessary Registry Keys with my Powershell Script..
function Test-RegistryValue {
param (
[parameter(Mandatory=$true)]
[ValidateNotNullOrEmpty()]$Path,
[parameter(Mandatory=$true)]
[ValidateNotNullOrEmpty()]$Value
)
try{
Get-ItemProperty -Path $Path | Select-Object -ExpandProperty $Value -ErrorAction Stop | Out-Null
return $true
}
catch{
return $false
}
}
#Certificate warning turn off
$exists = Test-RegistryValue -Path 'HKCU:\Software\Microsoft\Terminal Server Client' -Value 'AuthenticationLevelOverride'
if($exists -eq $False){
reg add "HKEY_CURRENT_USER\Software\Microsoft\Terminal Server Client" /v "AuthenticationLevelOverride" /t "REG_DWORD" /d 0 /f
}
Like this it works without this certificate notification!

Related

Setting autologon to a local user after joining to a domain

I'm building an application to assist in re-configuring devices on our network. I've got the entire script working except for setting the device to auto logon. Nothing I am trying seems to work. Now, the use is a little different, as the device will be joined to the domain, but logged on with a local user account. I'm trying to use the Sysinternals Autologon utility, but it is not working.
Here is the relevant code for logging on:
function Set-Autologon {
param (
[Parameter()][string]$domain
)
$exePath = "$scriptPath\$autologon"
$user = 'aloha'
$logonPath = "HKLM:\SOFTWARE\Microsoft\Windows NT\CurrentVersion\Winlogon"
$defaultdomain = "DefaultDomainName"
$alohass = '<very long string>' | ConvertTo-SecureString -Key $key
$alohaptr = [System.Runtime.InteropServices.Marshal]::SecureStringToCoTaskMemUnicode($alohass)
$aloharesult = [System.Runtime.InteropServices.Marshal]::PtrToStringUni($alohaptr)
LogInfo "Setting auto logon for $aloha user."
Start-Process -FilePath $exePath -ArgumentList "/accepteula", $user, $domain, $aloharesult -Wait -Verbose
}
The domain is being passed in as that is coming from a CSV file. The $key is set somewhere else in the script. I've tried with the /accepteula in both the front and the back.
What am I missing here?
Thanks
This should work with "/accepteula" as the last argument but, you can create a DWORD registry key in HKCU\Software\Sysinternals\AutoLogon for EulaAccept=1 before running the exe. You could also try starting the autologon.exe with the /accepteula flag and then immediately killing the process before running with the username/credentials arguments.

Check if given process is running with elevated right with powershell and Get-WmiObject

I have to following part of my script:
$active_processes = (Get-WmiObject -Class Win32_Process | where path -like $path | Select-Object -ExpandProperty Path | split-path -leaf | Select-Object -Unique)
It's working fine but I need to check if the process I get after all the script is running with elevated rights to launch another process with elevated rights if neccesary so it can interact with said process. I don't see any information about elevated rights with Get-WmiObject, I was wondering if I'm missing it or if there's another way to get that information
I don't need to run the powershell script as administrator. What I need is to find ff any executable requires elevated rights when launched and I need to find this information via powershell.
After some research on how windows knows if it needs admin to run an executable, I concluded that there are a couple ways but the most recommended and reliable is reading the executable manifest, so I wrote the following function:
function Get-ManifestFromExe{
Param(
[Parameter(Mandatory=$true,Position=0,ValueFromPipelineByPropertyName=$true)]
[Alias("Path")]
[ValidateScript({Test-Path $_ -IsValid})]
[String]$FullName
)
begin{
$stringStart = '<assembly'
$stringEnd = 'assembly>'
}
process{
$content = Get-Content $FullName -Raw
$indexStart = $content.IndexOf($stringStart)
$content = $content.Substring($indexStart)
$indexEnd = ($content.IndexOf($stringEnd)) + $stringEnd.Length
$content = $content.Substring(0,$indexEnd)
if($content -match "$stringStart(.|\s)+(?=$stringEnd)$stringEnd"){
return [XML]$Matches[0]
}
}
}
function Test-IsAdminRequired{
Param(
[Parameter(Mandatory=$true,Position=0)]
[XML]$xml
)
$value = $xml.assembly.trustInfo.security.requestedPrivileges.requestedExecutionLevel.level
if(-not [String]::IsNullOrEmpty($value)){
return ($value -eq "requireAdministrator" -or $value -eq "highestAvailable")
}else{
Write-Error "Provided xml does not contain requestedExecutionLevel node or level property"
}
}
$exe = '.\Firefox Installer.exe'
Get-ManifestFromExe -Path $exe
Test-IsAdminRequired -xml $exeManifest
It works by extracting the manifest XML from the executable and checking requestedExecutionLevel node's level property, the values accepted for this property are in this page, and quoted here:
asInvoker, requesting no additional permissions. This level requires
no additional trust prompts.
highestAvailable, requesting the highest permissions available to the
parent process.
requireAdministrator, requesting full administrator permissions.
So from this we can conclude that only highestAvailable and requireAdministrator would need admin privileges, so I check those, with that we will be done EXCEPT that some executables I tested (mostly installers) don't require admin to run but instead they prompt the UAC when they ruin their child executable, I don't really see a way to check this.. sorry.
BTW I really enjoyed this question (specially the research), hope this can help you.
SOURCES
What is the difference between "asInvoker" and "highestAvailable" execution levels?
reading an application's manifest file?
https://learn.microsoft.com/en-us/visualstudio/deployment/trustinfo-element-clickonce-application?view=vs-2019#requestedexecutionlevel
It's in the System.Security.Principal classes. This returns $true if the current user is elevated to local Administrator:
(New-Object System.Security.Principal.WindowsPrincipal([System.Security.Principal.WindowsIdentity]::GetCurrent())).IsInRole([System.Security.Principal.WindowsBuiltInRole]::Administrator)

Can PowerShell interact with RDP prompts?

I'm currently writing a script to automate a number of checks, I have a number of clients which I want to automatically log into one of their servers or use an app hosted via RDweb.
Right now my script works fine, however, I'm only able to get to the point that it'll start to execute the RDP pointer, I'm wondering if there's a way to hit "connect":
The method I'm currently using to run this:
[System.Diagnostics.Process]::Start("c:\file\path\file.rdp")
Is there a better way to run the .RDP file which will also allow you to "Connect"? I've also attempted to tick the "don't ask me" again, the next day it'll still prompt me with this message.
A solution I've found to start an RDP session that seems to work quite good is the following:
function Connect-RDP {
param (
[Parameter(Mandatory=$true)]
$ComputerName,
[System.Management.Automation.Credential()]
$Credential
)
# take each computername and process it individually
$ComputerName | ForEach-Object {
# if the user has submitted a credential, store it
# safely using cmdkey.exe for the given connection
if ($PSBoundParameters.ContainsKey('Credential'))
{
# extract username and password from credential
$User = $Credential.UserName
$Password = $Credential.GetNetworkCredential().Password
# save information using cmdkey.exe
cmdkey.exe /generic:$_ /user:$User /pass:$Password
}
# initiate the RDP connection
# connection will automatically use cached credentials
# if there are no cached credentials, you will have to log on
# manually, so on first use, make sure you use -Credential to submit
# logon credential
mstsc.exe /v $_ /f
}
}
Then you call it with Connect-rdp -ComputerName myserver -Credential (Get-Credential ).
Maybe you can adjust your script to use this cmdlet instead of your file.rdp.
I found the solution here:
https://www.powershellmagazine.com/2014/04/18/automatic-remote-desktop-connection/
Another way you could try is this:
[void][System.Reflection.Assembly]::LoadWithPartialName('System.Windows.Forms')
# Get the ID of the process
$WindowsHandle = Get-Process | Where-Object { $_.MainWindowTitle -Match 'Remote Desktop Connection' } | Select-Object -ExpandProperty Id
# Activate the window
$wshell = New-Object -ComObject wscript.shell;
$wshell.AppActivate($WindowsHandle) | Out-Null
# SendKey to connect
[System.Windows.Forms.SendKeys]::SendWait("%{c}")
%{c} stands for ALT+C
The modifier keys are:
Key | Code
-----------
SHIFT +
CTRL ^
ALT %

Negate having to Press Enter twice on PowerShell script

I am trying to run a PowerShell script daily through task scheduler, however the script will not run. When I enter the code below manually into PowerShell (as an administrator), it makes me press enter twice. I believe since i have to press enter twice is the reason it will not run through the task scheduler.
Is there a way to adjust my code to get this to work with the task scheduler?
I am running Windows 2012 R2 and Version 5.1 of PowerShell.
Please note that i ran the exact same script on my computer, which is Windows 10 and running version 5.1 of PowerShell, and it worked the correct way (only had to press enter once)
I expect to only press enter once to run my PowerShell script, but the actual output from the first time i press enter brings another line with just ">>" and then i press enter the second time and the script executes.
Powershell Script:
# Load WinSCP .NET assembly
Add-Type -Path "WinSCPnet.dll"
# Set up session options
$sessionOptions = New-Object WinSCP.SessionOptions -Property #{
Protocol = [WinSCP.Protocol]::Sftp
HostName = ""
UserName = ""
Password = ""
SshHostKeyFingerprint = ""
}
$session = New-Object WinSCP.Session
try
{
# Connect
$session.Open($sessionOptions)
# Transfer files
$session.PutFiles("", "").Check()
}
finally
{
$session.Dispose()
}
If a script requires user interaction, then it really should not be a scheduled task.
If you write a script that requires confirmation, then you need to look using -Confirm parameter.
See Are you sure? Using the -WhatIf and -Confirm parameters in PowerShel
Remove-MailContact -Identity “$sourceEmail” -Confirm:$Y -WhatIf
The cmdlet or code you write has to support it. For code you write, that means using advanced functions.
How to write a PowerShell function to use Confirm, Verbose and WhatIf
function Set-FileContent
{
[cmdletbinding(SupportsShouldProcess)]
Param
(
[Parameter(Mandatory = $true)]
[ValidateNotNullOrEmpty()]
[string]$Content,
[Parameter(Mandatory = $true)]
[ValidateScript( {Test-Path $_ })]
[string]$File
)
if ($PSCmdlet.ShouldProcess("$File" , "Adding $Content to "))
{
Set-Content -Path $File -Value $Content
}
}
See also ConfirmPreference

Using -Confirm in Powershell

I am trying to understand what the relationship between the $? and $lastexitcode variables versus the -Confirm flag in Powershell cmdlets.
Say for example you run a command with -confirm it will prompt you accordingly for action:
PS C:\temp> rm .\foo.txt -confirm
Confirm
Are you sure you want to perform this action?
Performing the operation "Remove Directory" on target "C:\temp\foo.txt".
[Y] Yes [A] Yes to All [N] No [L] No to All [S] Suspend [?] Help
(default is "Y"):n
PS C:\temp> $?
True
I understand that technically the command ran successfully, but if the user chose no then the command did not run.
My question is how to I obtain the user's answer to the -Confirm flag?
$?, $LastExitCode, and -Confirm are completely unrelated to each other.
$? is an automatic variable with a boolean value indicating whether or not the last (PowerShell) operation was executed successfully.
$LastExitCode is an automatic variable with the exit code of the external command that was last executed (an integer value).
-Confirm is a common parameter controlling whether or not a cmdlet prompts the user for confirmation of its action.
To my knowledge PowerShell does not store the answer given to a -Confirm prompt anywhere, so if you need that response for something else you'll have to prompt the user yourself, e.g. like this:
function Read-Confirmation {
Param(
[Parameter(Mandatory=$false)]
[string]$Prompt,
[Parameter(Mandatory=$false)]
[string]$Message
)
$choices = New-Object Collections.ObjectModel.Collection[Management.Automation.Host.ChoiceDescription]
$choices.Add((New-Object Management.Automation.Host.ChoiceDescription -ArgumentList '&Yes'))
$choices.Add((New-Object Management.Automation.Host.ChoiceDescription -ArgumentList '&No'))
-not [bool]$Host.UI.PromptForChoice($Message, $Prompt, $choices, 1)
}
$doRemove = if ($PSBoundParameters['Confirm'].IsPresent) {
Read-Confirmation -Prompt 'Really delete'
} else {
$true
}
if ($doRemove) {
Remove-Item .\foo.txt -Force
}
AFAIK, it is not possible to capture the user's response to the confirmation prompt; it is not a part of PowerShell's command history, and while you might be able to get the information from the buffer somehow that would only be supported in the default PowerShell host as other hosts will use different buffers. In this case it is probably best to either do a separate confirmation within your script using an if statement.
$userAnswer = Read-Host "Are you sure you wish to proceed?"
if($userAnswer -eq "yes"){
rm .\foo.txt
}
Then just use the $userAnswer variable to know what your user responded with. Alternatively you could determine their answer by checking to see if the operation was completed. This would be my preferred method as this way you are SURE that the file has been deleted rather than assuming so because the cmdlet successfully executed and the user confirmed (the reliability is probably not any different here considering that remove-item is incredibly well tested but it could make a difference if you are using a third-party library of some kind) that would look something like the below.
rm .\foo.txt -Confirm
if(Test-Path .\foo.txt){
$success = $false
} else {
$success = $true
}
and if you really need to know whether it failed to delete due to an error or the user saying no you could do something like
rm .\foo.txt -Confirm
if(Test-Path .\foo.txt){
$success = $false
} else {
$success = $true
}
if(!($success) -and (!($?))){
$status = "Previous command failed"
} elseif (!($success) -and $?){
$status = "User cancelled operation"
}
Hope that helps.