Perform a couple actions on PC's listed in text file

samiam41
samiam41 used Ask the Experts™
on
Hey Experts.  Trying my hand at a script that will clean-up profiles on the Windows 7 pc's in our training lab.  

I thought a script that pulled the computer names from the OU, put them in a text file and then perform a few actions on each pc in that file while recording the failure/success of the actions.  Something like A) ping the pc's to see if they are online and B) remove profiles. I put together a starting script but struggled with the profiles being removed from the computers that are pingable.

Get-ADComputer -Filter 'Name -like "TRN3*"' -SearchBase "OU=COMPUTERS,OU=TRAINING,OU=DEPTS,DC=LOCAL" -Property * | Select-Object name | out-file c:\tools\logs\output.txt

get-content -path c:\tools\logs\output.txt | foreach-object { ping $_ } > c:\tools\logs\pingresult.txt

Open in new window


End goal: powershell script that creates a logfile of computer names from the OU specified, verifies the computer is online via ping and if it is, removes the user profiles on each computer listed in the logfile.  Logging results to verify success.  

Again, any constructive criticism is welcome and I appreciate your time.

(edited for clarification)
Comment
Watch Question

Do more with

Expert Office
EXPERT OFFICE® is a registered trademark of EXPERTS EXCHANGE®

Author

Commented:
Still tweaking this and welcome a more tested script you may have

Get-ADComputer -Filter 'Name -like "TRN3*"' -SearchBase "OU=COMPUTERS,OU=TRAINING,OU=DEPTS,DC=LOCAL" -Property * | Select-Object -ExpandProperty name | out-file c:\tools\logs\testlog.csv

$TrainingPC = Get-Content "c:\tools\logs\testlog.csv" 
    ForEach ($computer in $TrainingPC)
        { 
          if (Test-Connection -ComputerName $computer -Count 1 -ErrorAction SilentlyContinue){
    Write-Host "$computer,up"
    gwmi win32_logicaldisk -ComputerName $computer -Filter "DeviceID='C:'" | Format-Table DeviceId, MediaType, @{n="Size";e={[math]::Round($_.Size/1GB,2)}},@{n="FreeSpace";e={[math]::Round($_.FreeSpace/1GB,2)}}
  }
  else{
    Write-Host "$computer,down"
    }

Open in new window

Instead of gwmi win32_logicaldisk use

gwmi -class Win32_UserProfile | Where { $_.SID.Length -gt 8 -and $_.Sid.Substring($_.Sid.Length-
5,4) -ne '-100'}  (gwmi -class Win32_UserProfile  -ComputerName $computer '").Delete()

Open in new window


Bit tricky to filter out local Windows internal like NetworkService profiles and the defaultuser profile.. test before running live.
As an alternative you can list the SIDs of your users, then filter to get only the domain users
:

 gwmi -class Win32_UserProfile -Computer "TargetComputer" | Where { $_.SID -like "your domain sid starts with%"} 

Open in new window

List local profiles

 
gwmi -class Win32_UserProfile -Computer "TargetComputer" |select sid,localpath

Open in new window



Hth
Learn Ruby Fundamentals

This course will introduce you to Ruby, as well as teach you about classes, methods, variables, data structures, loops, enumerable methods, and finishing touches.

Most Valuable Expert 2018
Distinguished Expert 2018

Commented:
This should do the trick.
It will skip system profiles, profiles that are still loaded, and the default administrator's profile.
It's in test mode and will only show what it would delete; uncomment line 12 ("#  [void]$_.Delete()") to run it for real:
$computerList = Get-Content C:\Temp\computerlist.txt
$logFile = 'C:\Temp\profiles.csv'
$computerList | ForEach-Object {
	$computerName = $_
	Write-Host "Processing $($computerName) ..."
	If (Test-Connection -ComputerName $computerName -Count 2 -Quiet) {
		Try {
			$profiles = Get-WmiObject -Class Win32_UserProfile -Filter "(Special='False') And (Loaded='False') And (Not (SID Like '%500'))" -ComputerName $computerName -ErrorAction Stop
			If ($profiles) {
				$profiles | ForEach-Object {
					$out = $_ | Select-Object -Property @{n='ComputerName'; e={$computerName}}, SID, LocalPath, RoamingConfigured, RoamingPath, Result
					Try {
#						[void]$_.Delete()
						$out.Result = "Profile deleted"
					} Catch {
						$out.Result = "ERROR: $($_.Exception.Message)"
					}
					$out
				}
			} Else {
				[PSCustomObject]@{ComputerName=$computerName; Result='Found no profiles to delete'}
			}
		} Catch {
			[PSCustomObject]@{ComputerName=$computerName; Result="ERROR: $($_.Exception.Message)"}
		}
	} Else {
		[PSCustomObject]@{ComputerName=$computerName; Result='No ping response'}
	}
} | Select-Object -Property ComputerName, SID, LocalPath, RoamingConfigured, RoamingPath, Result | Export-Csv -NoTypeInformation -Path $logFile

Open in new window

Author

Commented:
Thanks Experts!  Running through the suggestions now and will report back asap

Author

Commented:
oBdA, brilliant work as always!  I was curious how to capture the drive space before/after the profiles are wiped out.  I had this portion of code but wasn't sure where to inject with the code you provided.  

gwmi win32_logicaldisk -ComputerName $computer -Filter "DeviceID='C:'" | Format-Table DeviceId, MediaType, @{n="Size";e={[math]::Round($_.Size/1GB,2)}},@{n="FreeSpace";e={[math]::Round($_.FreeSpace/1GB,2)}}

Open in new window

Author

Commented:
@Michael Pfister, thank you for the coding.  I'm testing it once I wrap up the suggestion from oBdA.
Most Valuable Expert 2018
Distinguished Expert 2018

Commented:
Like this, for example; it'll add a separate row with a disk summary in the Results column once it's done with each computer.
$computerList = Get-Content C:\Temp\computerlist.txt
$computerList | ForEach-Object {
	$computerName = $_
	Write-Host "Processing $($computerName) ..."
	If (Test-Connection -ComputerName $computerName -Count 2 -Quiet) {
		Try {
			$diskC = Get-WmiObject  Win32_LogicalDisk -Filter "DeviceID='C:'" -ComputerName $computerName -ErrorAction SilentlyContinue
			$diskSize = [math]::Round($diskC.Size / 1GB, 2)
			$freeSpaceBefore = [math]::Round($diskC.FreeSpace / 1GB, 2)
			$profiles = Get-WmiObject -Class Win32_UserProfile -Filter "(Special='False') And (Loaded='False') And (Not (SID Like '%500'))" -ComputerName $computerName -ErrorAction Stop
			If ($profiles) {
				$profiles | ForEach-Object {
					$out = $_ | Select-Object -Property @{n='ComputerName'; e={$computerName}}, SID, LocalPath, RoamingConfigured, RoamingPath, Result
					Try {
#						[void]$_.Delete()
						$out.Result = "Profile deleted"
					} Catch {
						$out.Result = "ERROR: $($_.Exception.Message)"
					}
					$out
				}
			} Else {
				[PSCustomObject]@{ComputerName=$computerName; Result='Found no profiles to delete'}
			}
			$diskC = Get-WmiObject Win32_LogicalDisk -Filter "DeviceID='C:'" -ComputerName $computerName -ErrorAction SilentlyContinue
			$freeSpaceAfter = [math]::Round($diskC.FreeSpace / 1GB, 2)
			[PSCustomObject]@{ComputerName=$computerName; Result="SUMMARY: disk size $($diskSize)GB, free space before: $($freeSpaceBefore)GB, free space after: $($freeSpaceAfter)GB"}
		} Catch {
			[PSCustomObject]@{ComputerName=$computerName; Result="ERROR: $($_.Exception.Message)"}
		}
	} Else {
		[PSCustomObject]@{ComputerName=$computerName; Result='No ping response'}
	}
} | Select-Object -Property ComputerName, SID, LocalPath, RoamingConfigured, RoamingPath, Result 

Open in new window

Author

Commented:
Amazing script but I didn't see where the log file is listed now.
Most Valuable Expert 2018
Distinguished Expert 2018
Commented:
Temporary removal for testing ...
$computerList = Get-Content C:\Temp\computerlist.txt
$logFile = 'C:\Temp\profiles.csv'
$computerList | ForEach-Object {
	$computerName = $_
	Write-Host "Processing $($computerName) ..."
	If (Test-Connection -ComputerName $computerName -Count 2 -Quiet) {
		Try {
			$diskC = Get-WmiObject  Win32_LogicalDisk -Filter "DeviceID='C:'" -ComputerName $computerName -ErrorAction SilentlyContinue
			$diskSize = [math]::Round($diskC.Size / 1GB, 2)
			$freeSpaceBefore = [math]::Round($diskC.FreeSpace / 1GB, 2)
			$profiles = Get-WmiObject -Class Win32_UserProfile -Filter "(Special='False') And (Loaded='False') And (Not (SID Like '%500'))" -ComputerName $computerName -ErrorAction Stop
			If ($profiles) {
				$profiles | ForEach-Object {
					$out = $_ | Select-Object -Property @{n='ComputerName'; e={$computerName}}, SID, LocalPath, RoamingConfigured, RoamingPath, Result
					Try {
#						[void]$_.Delete()
						$out.Result = "Profile deleted"
					} Catch {
						$out.Result = "ERROR: $($_.Exception.Message)"
					}
					$out
				}
			} Else {
				[PSCustomObject]@{ComputerName=$computerName; Result='Found no profiles to delete'}
			}
			$diskC = Get-WmiObject Win32_LogicalDisk -Filter "DeviceID='C:'" -ComputerName $computerName -ErrorAction SilentlyContinue
			$freeSpaceAfter = [math]::Round($diskC.FreeSpace / 1GB, 2)
			[PSCustomObject]@{ComputerName=$computerName; Result="SUMMARY: disk size $($diskSize)GB, free space before: $($freeSpaceBefore)GB, free space after: $($freeSpaceAfter)GB"}
		} Catch {
			[PSCustomObject]@{ComputerName=$computerName; Result="ERROR: $($_.Exception.Message)"}
		}
	} Else {
		[PSCustomObject]@{ComputerName=$computerName; Result='No ping response'}
	}
} | Select-Object -Property ComputerName, SID, LocalPath, RoamingConfigured, RoamingPath, Result | Export-Csv -NoTypeInformation -Path $logFile

Open in new window

Author

Commented:
Thanks Experts for your help with this project!  I always learn so much from you all when you contribute.

Author

Commented:
If any of you have time for this question, I'd appreciate your help.

https://www.experts-exchange.com/questions/29142460/Include-details-into-log-file.html

Do more with

Expert Office
Submit tech questions to Ask the Experts™ at any time to receive solutions, advice, and new ideas from leading industry professionals.

Start 7-Day Free Trial