Remove specific Local user accounts from remote servers - powershell

We have a large number of servers with multiple accounts installed on the local machine, I need to remove the multiple local accounts from multiple servers and check they have been removed.
The only way I can see of doing this is by using PS-remoting (in our environment, it's totally locked down, so this is the only option)
As I understand you many new commands such as Remove-localuseraccount are only supported on new versions of PS (we have a project to upgrade to the better version)
$Computers = Get-Content C:\script\servers.txt
ForEach ($Computer in $Computers) {
$Session = New-PSSession -ComputerName $Computer
Invoke-Command -Session $session -ScriptBlock {
}
But what command can I run to check the multiple accounts list I have and remove if it finds any?

Desired State Configuration: Your life made easy
This will disable the local accounts and keep them that way utilizing DSC.
Setup.ps1
Install-Module -Name 'PSDscResources'
Set-Location -Path "$env:LocalAppData\Temp"
Configuration 'DisableDefaults'
{
Import-DscResource -ModuleName 'PSDscResources'
Node 'localhost'
{
User 'Default'
{
Username = 'DefaultAccount'
Disabled = $True
}
User 'Guest'
{
Username = 'Guest'
Disabled = $True
}
User 'Admin'
{
Username = 'Administrator'
Disabled = $True
}
}
}
DisableDefaults
Execution.ps1
Set-Location -Path "$env:LocalAppData\Temp\DisableDefaults"
$Computers = Get-Content -Path 'C:\script\servers.txt'
$Sessions = New-CimSession -ComputerName $Computers
Start-DscConfiguration -Path '.' -CimSession $Sessions -Wait -Force -Verbose
Remove-CimSession -CimSession $Sessions
You can cut the CimSession[] and just pass -ComputerName $Computers. Also, you can utilize the -Credential $PSCred argument.

Related

Problem with test-path on computer from another domain

Im trying to test a remote folder in a computer from another domain with -credential
This command works fine:
Invoke-Command -ComputerName "server" -credential domain\user -ScriptBlock {Test-Path -Path "\\server\s$\temp"}
But if i use it in a script fails:
$servers = Get-Content "servers.txt"
$Path = "\\D$\Temp"
$cred = "domain\user"
ForEach ($server in $servers) {
if (invoke-command -computername $server -credential $cred -ScriptBlock {Test-Path -Path "\\$server\$Path"})
}
PD: All this option works in a server of my domain without specify another credentials.
Besides the syntax issue with missing the script block after your if statement, this should work as long as you specify the variables as remote ones. Use $using or pass it as an argument with -ArgumentList.
$servers = Get-Content "servers.txt"
$Path = "\\c$\Temp"
$cred = "domain\user"
ForEach ($server in $servers) {
if (
invoke-command -computername $server -ScriptBlock {
Test-Path -Path "\\$using:server\$using:Path"
}
) { <#do code here#> }
}
If you run the shell with the proper credentials to begin with, all youd have to do is use Test-Path directly but I understand that you'd like to try using the -Credential parameter.

Getting The Hostname,Current DATE and Time for remote server using IP address in Powershell

I am new to powershell scriptting and what it can do. I have an IP address of remote server and I want to retrieve the date and time of that on my local machine which is connected to it using cisco any connect . Can I do it using powershell.
FYI, remoting through WinRM via IP, requires a -credential paramater value to be set. (Do this with $admin = Get-Credential and use -credential $admin as a parameter in the invoke-command)You can not remote via ip with your current credentials. Also when using invoke command, I would HIGHLY suggest using -sessionoption (new-pssessionoption -nomachineprofile) otherwise you're creating profiles on every machine, which not only takes more time, but also leaves massive trails of your work.
E.g. (with Nas answer used)
$admin = Get-Credential
$remoteIP = 'x.x.x.x'
Invoke-Command -ComputerName $remoteIP -credential $admin -sessionoption (new-pssessionoption -nomachineprofile) -ScriptBlock {
$env:COMPUTERNAME
Get-Date
}
if you want to use a ton of machines, you could do this...
$admin = Get-Credential
$remoteIP = "x.x.x.x","x.x.x.x"
foreach ($pc in $remoteIP) {
Invoke-Command -ComputerName $pc -credential $admin -sessionoption (new-pssessionoption -nomachineprofile) -ScriptBlock {
[pscustomobject][ordered]#{'Hostname'=$env:COMPUTERNAME
'Date'=Get-Date}
}
}
to speed it up, i would remove "env:computername" as it should return pscomputername anyhow
this should be tons faster
$remoteIP = "x.x.x.x","x.x.x.x"
foreach ($pc in $remoteIP) {
$object = Get-WmiObject -Class win32_operatingsystem -ComputerName $pc -Property localdatetime,__server
[pscustomobject][ordered]#{'computername'=$object.__server
'Date'=$object.converttodatetime($object.localdatetime)}
}
__Server is TWO underscores than the word server. NOT _Server but __Server
[pscustomobject] is short for new-object -typename psobject -property ...
and [ordered] just ensures your hashtable order is preserved.
Try this, should work if you have the necessary permissions and psremoting is enabled on the target server (Edit: convert ip to hostname)
$remoteIP = 'x.x.x.x'
$remoteServer = [System.Net.Dns]::GetHostByAddress($remoteIP)
Invoke-Command -ComputerName $remoteServer.HostName -ScriptBlock {
$env:COMPUTERNAME
Get-Date
}
Try it and we can help you from there, depending on the outcome.

Check the AppPool status through power-shell and start that on remote machine

The requirement is to extract the server name one by one and check the AppPool status, if that is found to be stopped, make it running. below code is not helping out.
$ErrorActionPreference = "Continue"
$status = gc -path "D:\Servers\server.txt"|ForEach-Object (invoke-command -ComputerName $_ -ScriptBlock {Import-Module Webadministration Get-WebAppPoolState -name (gc "D:\AppPool.txt")})
if ($status.value -eq "Started")
{
Write-Host ("ApppPool already running")
}
else
{
Invoke-Command -ScriptBlock {Start-WebAppPool}
Write-host ("AppPool has started successfully")
}
There were multiple problems with your code, I've gone through them individually so you can see what was stopping it from working correctly.
The syntax for foreach was wrong, you needed to use {} not () in this case. Normal brackets are only used like this ForEach ($number in $numArray ) {CODE} which you aren't.
You were checking $status outside the foreach loop - so it so was evaluating $status only once (with the final computers AppPool status) rather than for each computer.
Your second Invoke-Command didn't have a ComputerName parameter specified so was only running the command locally not against the remote computer, meaning the AppPool would never be started.
As you were specifying the AppPool name using gc "D:\AppPool.txt" this file would have to be present on every remote computer for it to work. I've changed this to be passed into the command as an argument so the file only needs to be on the computer running the script.
$Credentials = Get-Credential
$AppPools = Get-Content "D:\AppPool.txt"
$Servers = Get-Content -Path "D:\Servers\server.txt"
ForEach ($Server in $Servers) {
ForEach ($AppPool in $AppPools) {
$AppPoolState = Invoke-Command -ComputerName $Server -ScriptBlock {Import-Module WebAdministration; Get-WebAppPoolState -Name $args[0] } -ArgumentList $AppPool -Credential $Credentials
if ($AppPoolState.Value -eq "Started")
{
Write-Host "$AppPool AppPool already running on $Server"
}
else
{
Invoke-Command -ComputerName $Server -ScriptBlock {Start-WebAppPool -Name $args[0] } -ArgumentList $AppPool -Credential $Credentials
Write-Host "$AppPool AppPool started on $Server"
}
}
}
Note: I run a non-privileged account so have to supply Credentials. If the account you're running the script as has appropriate permissions to all the remote computers you can remove the three Credentials references.

Remote Registry using Enter-PSSession

I am trying to read strings in a remote registry. When I run the script I am working on, it connects to the workstation in the list, but it only reads the local computer when running, not the remote. any Ideas?
#create open dialog box
Function Get-FileName($initialDirectory)
{
[void] [Reflection.Assembly]::LoadWithPartialName( 'System.Windows.Forms' );
$d = New-Object Windows.Forms.OpenFileDialog;
$d.ShowHelp = $True;
$d.filter = "Comma Separated Value (*.csv)| *.csv";
$d.ShowDialog( ) | Out-Null;
$d.filename;
}
# Set Variables with arguments
$strFile = Get-FileName;
$strComputer = Get-Content $strFile;
$date = Get-Date -Format "MM-dd-yyyy";
$outputFile = "C:\PowerShell\Reports";
$cred = Get-Credential
foreach($computer in $strComputer)
{
Enter-PSSession $computer -Credential $cred
Set-Location HKLM:\SOFTWARE\Microsoft\Windows\CurrentVersion\Reliability
$systemInfo = Get-Item -Name LastComputerName
Write-Host $systemInfo
}
foreach($computer in $strComputer)
{
Enter-PSSession $computer -Credential $cred
..
..
}
The above code won't work. Enter-PSSession is not for using in a script. Anything written after that in a script won't run.
Instead, use Invoke-Command and pass rest of the script block as a parameter value. For example,
foreach ($computer in $strComputer) {
Invoke-Command -ComputerName $computer -Credential $cred -ScriptBlock {
Set-Location HKLM:\SOFTWARE\Microsoft\Windows\CurrentVersion\Reliability
$systemInfo = Get-Item -Name LastComputerName
Write-Host $systemInfo
}
}
As the comments already explained, Enter-PSSession is for interactive use. To read remote registry entries, there are several ways.
Use plain reg.exe, it works well enough. Like so,
foreach($computer in $strComputers) {
reg query \\$computer\hklm\software\Microsoft\Windows\CurrentVersion\Reliability /v LastComputerName
}
Use PSSessions. Create a session and Invoke-Command to read registry. Like so,
function GetRegistryValues {
param($rpath, $ivalue)
Set-Location $rpath
$systemInfo = (Get-ItemProperty .).$ivalue
Write-Host $systemInfo
}
$session = New-PSSession -ComputerName $computer
Invoke-Command -Session $session -Scriptblock ${function:GetRegistryValues} `
-argumentlist "HKLM:\SOFTWARE\Microsoft\Windows\CurrentVersion\Reliability",`
"LastComputerName"
Remove-PSSession $session
Use .Net classes, Microsoft.Win32.RegistryKey. Like so,
$sk = [Microsoft.Win32.RegistryKey]::OpenRemoteBaseKey([Microsoft.Win32.RegistryHive]::LocalMachine, $server)
$k = $sk.opensubkey("SOFTWARE\Microsoft\Windows\CurrentVersion\Reliability", $false)
write-host $k.getvalue("LastComputerName")

Get remote registry value

I have the below script that I want it to go out to multiple servers and get the value of a registry. Unfortunately it is currently just posting back the local registry value of the machine that I am running the script on.
How do I get the script to run against remote registry?
SCRIPT:
clear
#$ErrorActionPreference = "silentlycontinue"
$Logfile = "C:\temp\NEWnetbackup_version.log"
Function LogWrite
{
param([string]$logstring)
Add-Content $Logfile -Value $logstring
}
$computer = Get-Content -Path c:\temp\netbackup_servers1.txt
foreach ($computer1 in $computer){
$Service = Get-WmiObject Win32_Service -Filter "Name = 'NetBackup Client Service'" -ComputerName $computer1
if (test-connection $computer1 -quiet)
{
$NetbackupVersion1 = $(Get-ItemProperty hklm:\SOFTWARE\Veritas\NetBackup\CurrentVersion).PackageVersion
if($Service.state -eq 'Running')
{
LogWrite "$computer1 STARTED $NetbackupVersion1"
}
else
{
LogWrite "$computer1 STOPPED $NetbackupVersion1"
}
}
else
{
LogWrite "$computer1 is down" -foregroundcolor RED
}
}
You can try using .net:
$Reg = [Microsoft.Win32.RegistryKey]::OpenRemoteBaseKey('LocalMachine', $computer1)
$RegKey= $Reg.OpenSubKey("SOFTWARE\\Veritas\\NetBackup\\CurrentVersion")
$NetbackupVersion1 = $RegKey.GetValue("PackageVersion")
Try the Remote Registry Module, the registry provider cannot operate remotely:
Import-Module PSRemoteRegistry
Get-RegValue -ComputerName $Computer1 -Key SOFTWARE\Veritas\NetBackup\CurrentVersion -Value PackageVersion
If you have Powershell remoting and CredSSP setup then you can update your code to the following:
$Session = New-PSSession -ComputerName $Computer1 -Authentication CredSSP
$NetbackupVersion1 = Invoke-Command -Session $Session -ScriptBlock { $(Get-ItemProperty hklm:\SOFTWARE\Veritas\NetBackup\CurrentVersion).PackageVersion}
Remove-PSSession $Session
another option ... needs remoting ...
(invoke-command -ComputerName mymachine -ScriptBlock {Get-ItemProperty HKLM:\SOFTWARE\VanDyke\VShell\License -Name Version }).version
For remote registry you have to use .NET with powershell 2.0
$w32reg = [Microsoft.Win32.RegistryKey]::OpenRemoteBaseKey('LocalMachine',$computer1)
$keypath = 'SOFTWARE\Veritas\NetBackup\CurrentVersion'
$netbackup = $w32reg.OpenSubKey($keypath)
$NetbackupVersion1 = $netbackup.GetValue('PackageVersion')
If you need user's SID and browse remote HKEY_USERS folder, you can follow this script :
<# Replace following domain.name with yours and userAccountName with remote username #>
$userLogin = New-Object System.Security.Principal.NTAccount(“domain.name“,”userAccountName“)
$userSID = $userLogin.Translate([System.Security.Principal.SecurityIdentifier])
<# We will open HKEY_USERS and with accurate user’s SID from remoteComputer #>
$remoteRegistry = [Microsoft.Win32.RegistryKey]::OpenRemoteBaseKey(‘Users’,”remoteComputer“)
<# We will then retrieve LocalName value from Control Panel / International subkeys #>
$key = $userSID.value+”\Control Panel\International”
$openKey = $remoteRegistry.OpenSubKey($key)
<# We can now retrieve any values #>
$localName = $openKey.GetValue(‘LocaleName’)
Source : http://techsultan.com/how-to-browse-remote-registry-in-powershell/