How to validate local admin credentials against a set of servers - powershell

I have 60 servers, VMs to be particular. And I have a local admin username and password. Instead of logging on to 60 servers using these local admin creds, it would be better if there is a script to check if I could log on to these servers as a local admin using the local admin creds. To be precise, I want to check.if I can use this local admin creds to successfully log on to all 60 VMs.
I have googled but no luck. I know stackoverflow is not a place to directly ask for a piece of code, but in this case I am forced to. Even if you dont have a direct answer please direct me somewhere.
gc serverlist.txt | % {
$admin_share = '\\' + $_ + '\admin$'
if (Test-Path $admin_share) {
Write-Host "Access test passed on $($_)"
} else {
Write-Host "Access test failed on $($_)"
}
}

This is a variation of your attempt.
It assumes the same username and password for all computers.
#Get list of cserver names from file
$Servers = Get-Content -Path serverlist.txt
#Prompt user foe credentials
$Cred = Get-Credential
foreach ($Svr in $Servers)
{
#path to share (\\ServerName\Admin$)
$Path = '\\' + $Svr + '\Admin$'
Try
{
#Map admin share as PS Drive (NOT visable in the GUI)
#ErrorAction stop will jump to catch block if the connection is unsuccessfull
New-PSDrive -Name TEST -PSProvider FileSystem -Root $Path -Credential $Cred -ErrorAction Stop
#Success Message
Write-Output "Connection Successful $Svr"
#Remove drive before next loop
Remove-PSDrive -Name TEST
}
Catch
{
#Error message if connection fails
Write-Warning -Message "Connect failed $Svr"
}
}

If you have ICMP enabled, you could use Test-Connection cmdlet with the Credential switch. You can see more details in example 3 here:
https://learn.microsoft.com/en-us/powershell/module/microsoft.powershell.management/test-connection?view=powershell-6

Related

Password Reset Script Setup for Delegated Control User Group

I am trying to delegate a user group (non-administrators) to handle password reset for an organizational unit. Since I can't install Active Directory Users and Computers on the client computer, I wrote the two following scripts:
Test.ps1:
Invoke-Command -ComputerName DC -FilePath \\DC\SharedFolder\passwordreset.ps1
passwordreset.ps1:
Function GenerateStrongPassword ([Parameter(Mandatory=$true)][int]$PasswordLength)
{
Add-Type -AssemblyName System.Web
$PassComplexCheck = $false
do {
$newPassword=[System.Web.Security.Membership]::GeneratePassword($PasswordLength,1)
If ( ($newPassword -cmatch "[A-Z\p{Lu}\s]") `
-and ($newPassword -cmatch "[a-z\p{Ll}\s]") `
-and ($newPassword -match "[\d]") `
-and ($newPassword -match "[^\w]")
)
{
$PassComplexCheck=$True
}
} While ($PassComplexCheck -eq $false)
return $newPassword
}
Import-Module ActiveDirectory
$newPassword = GenerateStrongPassword(13)
$securePassword = ConvertTo-SecureString -AsPlainText $newPassword -Force
Set-ADAccountPassword -Identity test -NewPassword $securePassword -Reset
$newPassword
It works fine on the administrator account, but it doesn't work on any user of the user group I delegate control to. It complaints about...
PS C:\Users\User1\Downloads> powershell -executionpolicy bypass -file test.ps1
[DC] Connecting to remote server DC failed with the following error message : Access is
denied. For more information, see the about_Remote_Troubleshooting Help topic.
+ CategoryInfo : OpenError: (DC:String) [], PSRemotingTransportException
+ FullyQualifiedErrorId : AccessDenied,PSSessionStateBroken
I have verified that the user group has the following permission over the organizational unit:
Reset password
Read pwdLastSet
Write pwdLastSet
I also verified that the user group has read and read & execute permission on the shared folder and PowerShell script file. What other permission am I missing to get this to work for a non-administrator user account.
The main clue here is this:
[DC] Connecting to remote server DC failed with the following error message : Access is denied.
It looks like your users do not have permission to create remote PowerShell sessions on the DC. You'll need to grant them rights to execute commands on the DC.
If this is a Domain Controller you may want to consider setting up a session with a session configuration on the DC that they can import into their local session and use the ActiveDirectory cmdlets from there rather than allowing them to execute things on the DC itself. Or perhaps spin up a VM with the AD module installed that they can execute the script on. Most security personnel would frown at giving non-essential users access to execute things on your domain controller.

How to Check User's Rights via powershell on a remote or local machine

I have a script that needs to check the user' rights on the remote machine in order to confirm the user has the permissions to copy their files. When this part of the script runs, it fails 90% of the time unless the user is already an admin on the remote machine.
This is my code:
write-host Checking User Rights
#if the user provides and IP address, find the hostname
if ($sourceComputerName -match $ipPattern) {
Get-Hostname
}
else {
$global:fullHostName = $env:COMPUTERNAME
}
Write-host $sourceFolder
$permissionQuery = (Get-Acl $sourcefolder.substring(1, $sourceFolder.length - 2)).Access | Where-Object { $_.IdentityReference -match $adminusername } | Select-Object IdentityReference, FileSystemRights
if (!$permissionQuery) {
Invoke-Command -FilePath "$PSScriptRoot\LocalAdmin.ps1" -ComputerName $fullHostName -ArgumentList "$sourceRemotePath"
}
else {
write-host "Admin Rights Already Exist for $adminusername at $sourceRemotePath"
}
clear-host
Here is the Get-Hostname Function:
function global:Get-Hostname {
$queryHostname = [System.Net.DNS]::GetHostEntry($sourceComputerName) | Select-Object HostName | format-table -HideTableHeaders
$stringHostName = Out-String -InputObject $queryHostname
$splitHostName = $stringHostName.split(".", 2)
$global:fullHostName = $splitHostName[0] -replace '\s', ''
[void]$fullHostName
}
Here is the error:
[DESKTOPXXXX] Connecting to remote server DESKTOPXXXX failed with the following error message : Access is denied. For
more information, see the about_Remote_Troubleshooting Help topic.
+ CategoryInfo : OpenError: (DESKTOPXXXX:String) [], PSRemotingTransportException
+ FullyQualifiedErrorId : AccessDenied,PSSessionStateBroken
Note: I am one of the network admins and I have full admin rights on the machine I ran this script on
For effective permissions, try out Get-NTFSEffectiveAccess from the NTFSSecurity module.
The way you're currently checking permissions doesn't check for any groups that $adminusername is a member of, and may not give you accurate information.
The most common reason for "Access is denied" is that your current user is not an administrator on the remote machine, though there are other reasons listed in the Troubleshooting Guide:
Powershell remoting is not (or only partially) enabled on the remote machine.
WinRM service is not running
Remote firewall profile is in "Public network" mode (only accepts powershell remoting from the same subnet)
The current running credentials are invalid for some reason e.g. password expired.
You are double-hopping (remote from PC1 to PC2, then remote again to PC3)
First, try manually providing credentials:
$cred = Get-Credential -UserName Domain\AdminUser -Message Remote
Invoke-Command -Computername $sourceComputerName -Credential $cred -ScriptBlock {Hostname}
If you still get errors, try re-running the remote powershell setup on the remote machine (and restart it):
Enable-PSRemoting -Force

Using credentials with ADSI to reset a remote local computer account password

Trying to change a remote Windows Password using explicit credentials with PowerShell.
I've been able to make this work using the ADSI interface, but the script is running from a non-elevated account, and therefore does not have permissions. I need to ask the user for an elevated account, and then use that account when making the connection.
This works:
$server = "Server1"
$adminID = "Administrator"
$Password = "NewPassword"
$OldPassword = "OldPassword"
([ADSI] "WinNT://$server/$adminID").SetPassword($Password)
But, I need to also include the old password for the account, so that I have permissions to make the change.
Is there a way to make the connection to the server as $AdminD with the $OldPassword, and then change it to $NewPassword?
Found a solution.
$credential = New-Object System.Management.Automation.PSCredential($($server + "\" +$AdminID),$Oldpassword)
$pth = "\\$($server)\admin$"
write-host "Making connection to server with creds." -nonewline
# test for the drive, and remove if present.
if (![bool]([string]::IsNullOrEmpty($(get-psdrive x -ErrorAction SilentlyContinue).root)))
{
remove-PSDrive -Name X
write-host "Drive unmapped," -nonewline
}
New-PSDrive -Name X -PSProvider filesystem -Root $pth -Credential $credential | out-null
write-host " PS Drive established.. " -nonewline
([ADSI] "WinNT://$server/$adminID").SetPassword($Password)
By making a connection to the server first, the second call to reset the password uses the same credentials that are already established.
When done, I call the following to disconnect the drive..
# test for the drive, and remove if present.
if (![bool]([string]::IsNullOrEmpty($(get-psdrive x -ErrorAction SilentlyContinue).root)))
{
remove-PSDrive -Name X
write-host "Drive unmapped."
}
If there is a better way, I'd love to know what it is.. But this at least seemed to work.

New-PSDrive doesn't work when script is run from network share, but does work when run on the local machine

Context: IT staff may or may not log in with a local administrator account and run the following script. Due to the way Windows credential caching works on a local admin account, a simple copy and paste of the files without hardcoded credentials from a UNC path may not work occasionally.
My workaround for this issue was to just create a PSDrive for the session using a set of credentials that are reserved exclusively for scripting and domain joins.
IT staff access this script from the same server (fileserver05). The script attempts to make a temporary map of fileserver05. Is it just looping and confusing itself, or what?
Function Install {
Start-Process net -wait -ArgumentList "use X /delete" -ErrorAction SilentlyContinue
Remove-PSDrive X -Force -ErrorAction SilentlyContinue
Try {
$agentPass = Read-Host -AsSecureString -Prompt "Deployment operations supervisor password"
$agentUser = 'domain.com\agent'
$agentCred = New-Object -TypeName System.Management.Automation.PSCredential -ArgumentList $agentUser,$agentPass
New-PSDrive -Name "X" -PSProvider "FileSystem" -Root "\\fileserver05\Fileserver05\IT\Programs\Windows\Yardi CHECKscan Client" -Credential $agentCred -ErrorAction Stop
Write-Host 'Deploying CHECKscan client to local machine...'
Copy-Item -Path "X:\install.msi" -Destination "${env:TEMP}" -Force
Start-Process msiexec -Wait -ArgumentList "/i `"${env:TEMP}\install.msi`" /qn /norestart"
Write-Host 'Deploying connection settings to current and default user profile...'
Copy-Item -Path "X:\yCheckSettings.xml" -Destination "${env:APPDATA}" -Force
Copy-Item -Path "X:\yCheckSettings.xml" -Destination "C:\Users\Default\AppData\Roaming" -Force
}
Catch {
Write-Host ""
Write-Host "An error occured during installation" -BackgroundColor Red -ForegroundColor White
Write-Host "Ensure you have the correct credentials and a connection to the corporate network"
Write-Host "Ensure that paths to the installation files have not changed on the fileserver"
Write-Host ""
Install
}
}
Install
Please also note that ExecutionPolicy is set to Unrestricted.
If a staff member runs the script from the server, it fails and is unable to map the drive, therefore making the rest of the script not work. If a staff member takes the script and drags it to the local desktop, then runs it, it succeeds.
How can I make it so it can be ran from the server itself?

How to pre-fill RDP username & domain using mstsc in powershell

Currently, have two domains in which our users will have machines existing in either or. I am writing a powershell script in which I collect the user name and machine name. I think perform a test-connection to determine which domain the machine resides by pinging $computer.domain.com then if fails ping $computer.otherdomain.com.
Once I determine the domain I then take the username and place "domain\" + $username to prefill the domain name. I do the same with the provided and stored $machinename by performing this: $machinename + ".domain.com".
I don't want to store user's passwords
I've been trying to use cmdkey to associate the username with the machine and call mstsc (see example below):
cmdkey /generic:TERMSRV/$computername /user:"username"
mstsc /v:$computername
however when i run this, I get a logon attempt failure which isn't ideal.
I thought about trying to use the /prompt field after mstsc /v:$computername so:
mstsc /v:$computername /prompt
but this won't use the stored username, it will instead use the user profile i am currently running the command under.
I simply want my script to take the user's username and machine name, test and confirm which domain the machine resides in the back round, then have prefilled the username with the domain and just prompting the user to enter their password to continue.
Any advice on this would be greatly appreciated!
Here is the code i am working on below: ******
#Storing the provided username within variable $Username
$UserName = $UsernameTextbox.Text
Write-host "Username entered =" $UserName
#Storing the user's provided comuter name into $Machinename
$MachineName = $HostnameTextbox.Text
Write-host "Machinename entered =" $MachineName
#Deletes any previously stored cmdkeys that may interfere with the
cmdkey /list | ForEach-Object{if($_ -like "*Target:*"){cmdkey /del:($_ -
replace " ","" -replace "Target:","")}}
if (Test-Connection -ComputerName "$MachineName.domain.com" -Quiet ) {
$User = "domain\" + $UserName
$MachineName = $MachineName + ".domain.com"
Write-Host "Computer responded in domain"
}
else {
$User = "domain2\" + $UserName
$MachineName = $MachineName + ".domain2.com"
Write-Host "Computer is most likely in domain2"
}
cmdkey /add:$MachineName /user:$user
Write-host "Username with discovered domain name =" $User
Write-host "machine name after domain check =" $MachineName
$argumentslist = "/v:$MachineName " #took out /prompt
Start-Process -FilePath C:\Windows\System32\mstsc.exe -ArgumentList
"$argumentslist"