I am using the following script to retrieve Windows Defender status remotely.
$password = ConvertTo-SecureString “myPassword” -AsPlainText -Force
$credentials = New-Object System.Management.Automation.PSCredential (“myUserNamer”, $password)
$sessionOption = New-CimSessionOption -Protocol WsMan
$session = New-CIMSession -ComputerName myMachineName -Credential $credentials -SessionOption
Get-MpPreference -CimSession $session
However, I am quite new to PowerShell scripting and related protocols. Is this the best way of retrieving this information when I may have to run it over hundreds of computers?
Does it need to be for all the machines or selected ones?
For example:
You could run a remote session on the machine you need and then run the command.
Enter-PSSession [VMname]
Get-MpComputerStatus
Replace [VMname] with the name of the VM/Computer you're looking for.
Enter-PSSession Computer-01
Get-MpComputerStatus
If that's what you're looking for.
Related
So I have automation that logs into a Windows Server 2019 machine as one user, but then needs to run a command (Invoke-AdminCommand is application specific, not a built-in Windows cmdlet) as an admin user (and I do not want to add the logged in user as an Admin). I've followed answers from here (if you think this is a duplicate question) and none have worked. In the script I do a "whoami" to be sure the session is the correct user, and it is. But the command returns an application specific error stating the user does not have the correct permissions. If I RDP into the same machine as the admin user and run the same command through a Powershell CLI - it works fine.
$username = "domain\adminUser"
$password = "**********" | ConvertTo-SecureString -AsPlainText -Force
$cred = New-Object System.Management.Automation.PSCredential -ArgumentList $username,$password
$s = New-PSSession -credential $cred
$sc = {
whoami
Invoke-AdminCommand -Register -Verbose
}
Invoke-Command -Session $s -Scriptblock $sc
Remove-PSSession $s
You may be hitting the double-hop problem. You are remoting to another server to run another command which itself requires authentication. If you can't lean on CredSSP (security risk) or proper account delegation (potentially high overhead in effort to maintain delegations at volume but this is the correct way to go about it).
Note: Basic auth will also work around this issue but I highly highly highly do not recommend using basic auth without at least setting up WinRM over SSL and removing non-HTTPS WinRM listeners.
Whether you are using Kerberos (without proper delegation or CredSSP) or NTLM (at all as NTLM cannot forward tokens) as the authentication scheme you can work around this by passing the credential information into Invoke-Command and building the credential in that script block, and using Start-Process to start it as a different user. Note that if you needed to elevate for UAC, the code would be different and this code will only work when you don't need UAC elevation:
# We will create the SecureString inside the Invoke-Command block
$password = "********"
# Use of a Dictionary instead of positional arguments and `param` in the block
# is a little trick you can use here.
Invoke-Command -Session $s -ArgumentList #{ Username = $username; Password = $password } {
$cred =
[PSCredential]::new($args.Username, ( $args.Password | ConvertTo-SecureString -AsPlainText -Force ))
# Placeholder for next part
}
So this is the boilerplate for what you want. You send the credentials to the remote server and build it there. How you execute this at # Placeholder for next part will depend on what exactly you are running:
External Command (executable)
Use Start-Process to run the program as the other user
Start-Process -Wait -Credential $cred program.exe -ArgumentList "arguments to the program here"
Any cmdlet which accepts a -Credential parameter or any command which accepts username and password arguments
Pass the credential argument directly to the cmdlet/function, or pass $args.Username and $args.Password to an external command which has username/password parameters directly. The below however exemplifies using this with a cmdlet and the -Credential parameter.
# Note that some cmdlets don't take a credential for whatever reason
# and may have -Username and -Password arguments instead.
Invoke-AdminCommand -Credential $cred -Register -Verbose
Any Function or Cmdlet which does not accept a -Credential parameter or username/password arguments
This is similar to the first example, but this example specifically targets running a bit of PowerShell code as another user for the code you want.
# This can be invoked without splatting but am using splatting for readability
$spArgs = #{
Credential = $cred
FilePath = 'powershell.exe' # You can use `pwsh.exe` for PS Core if necessary
ArgumentList = "-Command ""exampleProgram.exe -username $($args.Username) -password $($args.Password)"""
Wait = $true
NoNewWindow = $true
}
Start-Process powershell.exe
I have a task to check the username and password on multiple servers and report the result.
So basically i have a list of IP's And I want I have the same user and password and need to see which authenticate and which don't.
This is what I found so far but it doesn't seems to work it prompts me for password every-time.
$listofServers = Import-Csv '.\Windows Servers.csv'
$username = username
$password = password
foreach($server in $listofServers.ip)
{
try{
$Credentials = Get-Credential $server\$username $password
}
Catch
{
$errorMsg = $_.Exception.Message
}
}
As said more than once, but never too much, you should NOT store a password in plain text. Probably the simplest of the many ways you can store it as a clixml file encrypted by a specific account. You can limit access to the location it's saved to that same account that can decrypt it.
You'll need to use the same username/password in combination with the computer name/IP to build an actual PSCredential object. I assume IP as your code shows $listofservers.ip - if the CSV header is not IP, update the code accordingly. I added some feedback to show you which computer and user connected and the fact that it's able to run the command remotely proves the connection was successful.
$username = 'localadmin'
$password = ConvertTo-SecureString 'PlaintextIsaNoNo' -AsPlainText -Force
Import-Csv '.\Windows Servers.csv' | ForEach-Object {
$cred = New-Object System.Management.Automation.PSCredential ("$($_.ip)\$username", $password)
Try
{
Invoke-Command -ComputerName $_.ip -ScriptBlock {
Write-Host Sucessfully connected to $env:computername as $(whoami) -ForegroundColor Green
} -Credential $cred
}
Catch
{
$PSItem.Exception.Message
}
}
The problem with the above code is it will run one PC at a time. Invoke-Command runs asynchronously if you just give it a list of computers (up to 32 by default on PS5.1) If you change the structure, this will run much faster. This requires a pretty well known trick which is to provide the username as .\username which designates it's a local account. I've tested and it works for me, so please let me know if you see otherwise.
$username = 'localadmin'
$password = ConvertTo-SecureString 'PlaintextIsaNoNo' -AsPlainText -Force
$serverlist = Import-Csv '.\Windows Servers.csv'
$cred = New-Object System.Management.Automation.PSCredential (".\$username", $password)
Try
{
Invoke-Command -ComputerName $serverlist.ip -ScriptBlock {
Write-Host Sucessfully connected to $env:computername as $(whoami) -ForegroundColor Green
} -Credential $cred
}
Catch
{
$PSItem.Exception.Message
}
Update
Removing the previous answer because of our threads below.
Here's your issue.
You cannot do things the way you are trying because of how Windows security boundaries proper works and you'd also have to set up PowerShell Remoting properly.
You have not said whether you are in a domain or in a Workgroup scenario. Hence the previous statement about setting up PSRemoting properly.
Because you are using a local account, this is like using Workgroup mode in PSRemoting and that requires additional settings to be in place. See the details regarding 'TrustedHosts'.
about_Remote_Troubleshooting - PowerShell | Microsoft Docs
Doing a logon to a remote host as you are trying will popup the Logon dialog (Gina) by design.
On your admin machine, try it this way... (tested and validated as working)
### PSRemoting - using local machine accounts
$Creds = Get-Credential -Credential $env:USERNAME
Enable-PSRemoting -SkipNetworkProfileCheck -Force
Get-Item -Path 'WSMan:\localhost\Client\TrustedHosts'
Set-Item -Path 'WSMan:\localhost\Client\TrustedHosts' -Value '*' -Force
Get-Item -Path 'WSMan:\localhost\Client\TrustedHosts'
$TargetList = 'Lab01','172.0.0.10'
$TargetList |
ForEach-Object {
"Validating logon for $($Creds.Username) on target $PSItem"
Try
{
New-PSSession -ComputerName $PSItem -Credential $Creds
Get-PSSession | Remove-PSSession
}
Catch {$PSItem.Exception.Message}
}
Set-Item -Path 'WSMan:\localhost\Client\TrustedHosts' -Value '' -Force
# Results
<#
Validating logon for postanote on target Lab01
Id Name ComputerName ComputerType State ConfigurationName Availability
-- ---- ------------ ------------ ----- ----------------- ------------
26 WinRM26 Lab01 RemoteMachine Opened Microsoft.PowerShell Available...
Validating logon for postanote on target 172.0.0.10
27 WinRM27 172.0.0.10 RemoteMachine Opened Microsoft.PowerShell Available...
#>
Update
Here's a tweak to Doug and my approach and dropping the need to have PSRemoting proper to be involved at all. Again, tested and validated. Except for the one time prompt for the creds, no embedded plain text passwords/files/registry/CredMan storage and retrieval, etc needed.
$Creds = Get-Credential -Credential $env:USERNAME
$TargetList |
ForEach-Object {
"Processing hostname $PSItem"
Try
{
$cred = New-Object System.Management.Automation.PSCredential ("$PSItem\$($Creds.UserName)", $Creds.Password)
(Get-HotFix -ComputerName $PSItem -Credential $cred)[0]
}
Catch {$PSItem.Exception.Message}
}
# Results
<#
Processing hostname Lab01
Source Description HotFixID InstalledBy InstalledOn
------ ----------- -------- ----------- -----------
Lab01 Update KB4576478 NT AUTHORITY\SYSTEM 9/10/2020 12:00:00 AM
Processing hostname 172.0.0.10
Lab01 Update KB4576478 NT AUTHORITY\SYSTEM 9/10/2020 12:00:00 AM
#>
• Tip: Work Remotely with Windows PowerShell without using Remoting or
WinRM
https://technet.microsoft.com/en-us/library/ff699046.aspx
Some cmdlets have a –ComputerName parameter that lets you work with a remote
computer without using Windows PowerShell remoting. This means you can use
the cmdlet on any computer that is running Windows PowerShell, even if the
computer is not configured for Windows PowerShell remoting. These cmdlets
include the following:
• Get-WinEvent
• Get-Counter
• Get-EventLog
• Clear-EventLog
• Write-EventLog
• Limit-EventLog
• Show-EventLog
• New-EventLog
• Remove-EventLog
• Get-WmiObject
• Get-Process
• Get-Service
• Set-Service
• Get-HotFix
• Restart-Computer
• Stop-Computer
• Add-Computer
• Remove-Computer
• Rename-Computer
• Reset-ComputerMachinePassword
I am trying to create a script which adds currently logged on user account to local admin group which is to be deployed as SCCM package to freshly deployed computers in one particular AD OU group. I have encoded a service account credentials using a .key seed and stored them in a .txt file. Unfortunately I'm unable to retrieve/pass the current user account to aforementioned command.
I've tried running package with administrative rights option enabled, skipping credential encode and using various methods without success outside of lab, hence why I had to request a service account which would have enough rights to get the job done. Ive also tried various ways of identifying user accounts, however this is the only one which retrieves the actual account of windows user rather than the one under which PS session is running.
$User = [System.Security.Principal.WindowsIdentity]::GetCurrent().Name
$Computer = $env:COMPUTERNAME $svcAcc = "xxx\xx-xx" $PasswordFile = ".\Password.txt" $KeyFile = ".\AES.key" $key = Get-Content $KeyFile
$Cred = New-Object -TypeName System.Management.Automation.PSCredential -ArgumentList $svcAcc,(Get-Content $PasswordFile | ConvertTo-SecureString -Key $key)
Invoke-Command -ComputerName $Computer -Credential $Cred -ScriptBlock {Add-LocalGroupMember -Group "Administratorer" -Member $User}
I expected the $User variable to be passed correctly as when I run [System.Security.Principal.WindowsIdentity]::GetCurrent().Name selection, correct details are shown. Instead I get an error
Cannot validate argument on parameter 'Member'. The argument is null or empty"
Any pointers would be greatly appreciated
Everything within the scriptblock is executed on the remote machine. That remote machine does not have access to the local variable "$User"
Use the -ArgumentList parameter to pass the $user variable to the Scriptblock.
Invoke-Command -ComputerName $Computer -ScriptBlock {Add-LocalGroupMember -Group "Administratorer" -Member $args[0]} -ArgumentList $User
I am trying to launch a process in Windows under specific user account.
While launching process with ProcessStartInfo works locally and when you have the active interactive session. It's not working in remote scenario where the active session is not present.
On Remote machine, Service ABC is running under admin account (domain\adminuser), which is launching the powershell.exe under same admin account to launch the script and drive the flow.
In the script, I am tried to launch process [non-interactive], but failed to launch the same.
$Processinfo = New-Object System.Diagnostics.ProcessStartInfo
$Processinfo.UseShellExecute = $false
$Processinfo.LoadUserProfile = $false
$Processinfo.CreateNoWindow = $true
$Processinfo.Username = "domain\user"
$Processinfo.PasswordInClearText = "testpass"
$Processinfo.FileName = "abc.exe"
I don't see a reason why I am not allowed to launch non-interactive process from Session 0
To run locally, you can simply use Start-Process
$Credentials = Get-Credentials
Start-Process -Credential $Credentials -FilePath 'C:\Windows\notepad.exe'
For Remote Machine you can use WMI Create using the -List Parameter:
(Get-WmiObject win32_process -ComputerName $computer -Credential $Credentials -List).Create("notepad")
Short but complicated question : is there any way to log on to a Domaincontroler with Servername\Username?
Ive got a Script wich specificly uses a Local Account (since 99% of our Servers are not in a Domain + you can create Local user accounts on almost Every Windows machine, but not on a DC sadly).
So basicly what im asking is : is there a way to trick a DC to accept Servername\Username as a domain login? is there a way by rights? Changing the Script is not an option sadly since the infrastructure behind it is too big to change, and i dont want to add a server specific exception.
Update : It worked on 2 2003 DCs but still no luck with the 2008 DC. is/was there a Change in microsofts server Policy?
the Script part im Using :
$SecurePassWord = ConvertTo-SecureString -AsPlainText $($Row['Passwort']) -Force
$Cred = New-Object -TypeName "System.Management.Automation.PSCredential" -ArgumentList "$($Row['ServerName'])\$($Row['Benutzername'])", $SecurePassWord
$pssessionoption = new-pssessionoption -operationtimeout 7200000 -IdleTimeout 7200000
Try {
$Session = New-PSSession -ComputerName $($Row['ServerName']) -credential $Cred -sessionOption $pssessionoption -EA Stop
Remove-PSSession -Session $Session
}
Catch [system.exception]
{
write-host "not working"
}
Anybody has an Explanation?
No, you cannot create a local users on a DC and therefore cannot use local credentials. Ever. This question should really be Server Fault.