I have powershell script to pull down hotfixID, installedon, lastbootuptime and freespace in C drive. (I googled around and changed couple of things I need.) when the Pc is not reachable it will
Write-Warning "$_ cannot be reached, skipping."
I also want to capture the computer name of the failed PC to my CSV. I tried
| Export-Csv C:\test\computerDetails.csv -NoTypeInformation
or append but seems like its not working. can someone please help? below is my whole script.
(Get-Content C:\test\serverlist.txt).Trim() | ForEach {
If (Test-Connection -ComputerName $_ -Count 1 -Quiet)
{
$update = Get-CimInstance Win32_QuickFixEngineering -ComputerName $_ | Sort-Object InstalledOn -Descending | Select-Object -First 1
$os = Get-CimInstance win32_operatingsystem -ComputerName $_
$disk = Get-WmiObject Win32_LogicalDisk -ComputerName $_ -Filter "DeviceID='C:'"
$props = #{
ComputerName = $_
HotFixID = $update.HotFixID
InstalledOn = $update.InstalledOn
lastbootuptime = $os.LastBootUpTime
FreeSpace_GB = $disk.FreeSpace / 1GB
}
New-Object PsObject -Property $props
}
Else {
Write-Warning "$_ cannot be reached, skipping." | Export-Csv C:\test\computerDetails.csv -NoTypeInformation
}
} | Sort ComputerName |
Select ComputerName,HotFixID,InstalledOn,lastbootuptime,FreeSpace_GB |
Export-Csv C:\test\computerDetails.csv -NoTypeInformation
Main problem with adding it to the CSV is that it is a string. If you treat the erroneous machines the same as successful ones, then you can throw them in the same CSV.
I have added an ArrayList there as the storage variable and then for each computer it creates a temp PSObject to store your results in, overwriting the variable each loop but not before dumping the variable into the ArrayList for export at the end.
$Errors = New-Object System.Collections.ArrayList
(Get-Content C:\test\serverlist.txt).Trim() | ForEach {
$Temp = New-Object -TypeName PSObject
If (Test-Connection -ComputerName $_ -Count 1 -Quiet) {
$update = Get-CimInstance Win32_QuickFixEngineering -ComputerName $_ | Sort-Object InstalledOn -Descending | Select-Object -First 1
$os = Get-CimInstance win32_operatingsystem -ComputerName $_
$disk = Get-WmiObject Win32_LogicalDisk -ComputerName $_ -Filter "DeviceID='C:'"
$props = [ordered]#{
ComputerName = $_
HotFixID = $update.HotFixID
InstalledOn = $update.InstalledOn
lastbootuptime = $os.LastBootUpTime
FreeSpace_GB = $disk.FreeSpace / 1GB
Error = "Success"
}
$Temp | Add-Member -NotePropertyMembers $props -TypeName temp
} Else {
$props = [ordered]#{
ComputerName = $_
Error = "Cannot be reached"
}
$Temp | Add-Member -NotePropertyMembers $props -TypeName temp
Write-Warning "$_ cannot be reached, skipping."
}
$Errors.Add($Temp) > $null
}
$Errors | Export-Csv C:\temp\computerDetails.csv -NoTypeInformation -Append
Related
I'm trying to build a powershell script that I can use to delete all or some of the user profiles on multiple pc's since they often cause the drives to go full.
I found the current script which I got to work for me, but I'd like to optimize it so I can input or import a list of computers where I want him to remove all the user profiles from.
Can you guys help me to input this feature?
Current Code:
$ExcludedUsers ="admin","test"
$RunOnServers = $false
[int]$MaximumProfileAge = 0 # Profiles older than this will be deleted
$osInfo = Get-CimInstance -ClassName Win32_OperatingSystem
if ($RunOnServers -eq $true -or $osInfo.ProductType -eq 1) {
New-EventLog -LogName Application -Source "Stone Profile Cleanup" -ErrorAction SilentlyContinue
$obj = Get-WMIObject -class Win32_UserProfile | Where {(!$_.Special -and $_.Loaded -eq $false )}
#$output = #()
foreach ($littleobj in $obj) {
if (!($ExcludedUsers -like $littleobj.LocalPath.Replace("C:\Users\",""))) {
$lastwritetime = (Get-ChildItem -Path "$($littleobj.localpath)\AppData\Local\Microsoft\Windows\UsrClass.dat" -Force ).LastWriteTime
if ($lastwritetime -lt (Get-Date).AddDays(-$MaximumProfileAge)) {
$littleobj | Remove-WmiObject
# $output += [PSCustomObject]#{
# 'RemovedSID' = $littleobj.SID
# 'LastUseTime' = $litteobj.LastUseTime
# 'LastWriteTime' = $lastwritetime
# 'LocalPath' = $littleobj.LocalPath
# }
}
}
}
#$output | Sort LocalPath | ft
#$output | Sort LocalPath | ft * -AutoSize | Out-String -Width 4096 | Out-File -filepath "C:\MyOutput.TXT" -append -Encoding Unicode
Write-EventLog –LogName Application –Source "Stone Profile Cleanup" –EntryType Information –EventID 1701 -Category 2 -Message ("Profiles older than $MaximumProfileAge days have been cleaned up")
}$ExcludedUsers ="adminbholemans","testbholemans1"
$RunOnServers = $false
[int]$MaximumProfileAge = 0 # Profiles older than this will be deleted
$osInfo = Get-CimInstance -ClassName Win32_OperatingSystem
if ($RunOnServers -eq $true -or $osInfo.ProductType -eq 1) {
New-EventLog -LogName Application -Source "Stone Profile Cleanup" -ErrorAction SilentlyContinue
$obj = Get-WMIObject -class Win32_UserProfile | Where {(!$_.Special -and $_.Loaded -eq $false )}
#$output = #()
foreach ($littleobj in $obj) {
if (!($ExcludedUsers -like $littleobj.LocalPath.Replace("C:\Users\",""))) {
$lastwritetime = (Get-ChildItem -Path "$($littleobj.localpath)\AppData\Local\Microsoft\Windows\UsrClass.dat" -Force ).LastWriteTime
if ($lastwritetime -lt (Get-Date).AddDays(-$MaximumProfileAge)) {
$littleobj | Remove-WmiObject
# $output += [PSCustomObject]#{
# 'RemovedSID' = $littleobj.SID
# 'LastUseTime' = $litteobj.LastUseTime
# 'LastWriteTime' = $lastwritetime
# 'LocalPath' = $littleobj.LocalPath
# }
}
}
}
#$output | Sort LocalPath | ft
#$output | Sort LocalPath | ft * -AutoSize | Out-String -Width 4096 | Out-File -filepath "C:\MyOutput.TXT" -append -Encoding Unicode
Write-EventLog –LogName Application –Source "Stone Profile Cleanup" –EntryType Information –EventID 1701 -Category 2 -Message ("Profiles older than $MaximumProfileAge days have been cleaned up")
}
I found this piece of code for the computer input but I'm not sure how I can implement it properly.
Get-CimInstance -ComputerName SRV1,SRV2,SRV3 -Class Win32_UserProfile | Where-Object { $_.LocalPath.split('\')[-1] -eq 'UserA' } | Remove-CimInstance
Thanks for the help everyone.
Get-CimInstance -ComputerName SRV1,SRV2,SRV3 -Class Win32_UserProfile | Where-Object { $_.LocalPath.split('')[-1] -eq 'UserA' } | Remove-CimInstance
Do u test it before? Work OK?
I'm trying to get the hostname and the MAC address from all PCs in the Active Directory. I know that MAC addresses are not in the Activce Directory. That's why I already used a small script from someone else. The point is that I have to make a list of hostnames, which I can do, but then the other script runs into a problem because some computers are not online.
Can anyone help me get a list with only the pc's that are online?
This is the part that searches the list I create with hostnames.
$Computers = Import-CSV C:\Users\admin_stagiair\Desktop\Computers.txt
$result = #()
foreach ($c in $Computers){
$nic = Invoke-Command {
Get-WmiObject Win32_NetworkAdapterConfiguration -Filter 'ipenabled = "true"'
} -ComputerName $c.Name
$x = New-Object System.Object | select ComputerName, MAC
$x.Computername = $c.Name
$x.Mac = $Nic.MACAddress
$result += $x
}
$result | Export-Csv C:\Users\admin_stagiair\Desktop\Computers.csv -Delimiter ";" -NoTypeInformation
And this is the part that I tried to make search the list and filter out the online computers, which absolutely does not work and I can't figure out how to do it.
$Computers = Import-Csv C:\Users\admin_stagiair\Desktop\Computers.txt
foreach ($c in $Computers) {
$ping = Test-Connection -Quiet -Count 1
if ($ping) {
$c >> (Import-Csv -Delimiter "C:\Users\admin_stagiair\Desktop\online.txt")
} else {
"Offline"
}
}
Last bit, this is the part I use to create a list of all computers in the Active Directory.
Get-ADComputer -Filter {enabled -eq $true} -Properties * |
select Name > C:\Users\(user)\Desktop\Computers.txt
If you only want one property from Get-ADComputer don't fetch all
a computer could have more than one MAC, to avoid an array be returned join them.
$result += inefficiently rebuilds the array each time, use a PSCustomObject instead.
Try this (untested):
EDIT: first test connection, get MAC only when online
## Q:\Test\2018\09\18\SO_52381514.ps1
$Computers = (Get-ADComputer -Filter {enabled -eq $true} -Property Name).Name
$result = ForEach ($Computer in $Computers){
If (Test-Connection -Quiet -Count 1 -Computer $Computer){
[PSCustomPbject]#{
ComputerName = $Computer
MAC = (Invoke-Command {
(Get-WmiObject Win32_NetworkAdapterConfiguration -Filter 'ipenabled = "true"').MACAddress -Join ', '
} -ComputerName $Computer)
Online = $True
DateTime = [DateTime]::Now
}
} Else {
[PSCustomPbject]#{
ComputerName = $Computer
MAC = ''
Online = $False
DateTime = [DateTime]::Now
}
}
}
$result | Export-Csv C:\Users\admin_stagiair\Desktop\Computers.csv -Delimiter ";" -NoTypeInformation
What about trying something like this:
# Get all computers in list that are online
$Computers = Import-Csv C:\Users\admin_stagiair\Desktop\Computers.txt |
Select-Object -ExpandProperty Name |
Where-Object {Test-Connection -ComputerName $_ -Count 1 -Quiet}
# Grab the ComputerName and MACAddress
$result = Get-WmiObject -ComputerName $computers -Class Win32_NetworkAdapterConfiguration -Filter 'ipenabled = "true"' |
Select-Object -Property PSComputerName, MacAddress
$result | Export-Csv C:\Users\admin_stagiair\Desktop\Computers.csv -Delimiter ";" -NoTypeInformation
I am very close to what I am looking for, I have all of the correct data and it is just not formatting correctly. Currently it is all in one column, and what I would like is for the headers to be in a row, and then each entry to be in its own row as well. Here is my current code:
$servers = Get-ADComputer -Filter "Name -like 'f****p*'" | Sort-Object | Select -ExpandProperty Name
$servers | foreach {
$server = $_
$serverIP = Test-Connection -ComputerName $server -Count 1 | Select -ExpandProperty IPV4Address
$serverIPString = $serverIP.IPAddresstoString
$scope = Get-DhcpServerv4Scope -ComputerName $server
$options = Get-DhcpServerv4OptionValue -ComputerName $server
New-Object -TypeName psobject -Property #{
ServerName = $server
ServerIP = $serverIPString
ScopeName = $scope.Name | Out-String
StartIP = $scope.StartRange.IPAddressToString | Out-String
EndIP = $scope.EndRange.IPAddressToString | Out-String
SubnetMask = $scope.SubnetMask.IPAddressToString | Out-String
Duration = $scope.LeaseDuration.Days | Out-String
OptionName = $options.Name | Out-String
OptionID = $options.OptionID | Out-String
OptionValue = $options.Value | Out-String
}
} | Select-Object ServerName, ServerIP, ScopeName, StartIP, EndIP, SubnetMask, Duration, OptionName, OptionID, OptionValue | Out-File C:\temp\FPScopes.csv
Currently the output looks like this example (using Duration and Options as an example, as it has the most generic data to share):
What I am looking for would be to have each object type as a column header, and have the entries in a separate row underneath the header:
Etc....
Any assistance would be greatly appreciated.
Thank you! :)
Ry
My final code, after help from this forum:
Add-Content -Value "ServerName,ServerIP,ScopeName,StartRange,EndRange,SubnetMask,Duration,OptionName,OptionID,Value" -Path c:\temp\POSScopes.csv
Get-ADComputer -Filter {Name -like 'p****p01' -or Name -like 'p****p02' -or Name -like 'q****001' -or Name -like 'q****002'} | Sort-Object | Select -ExpandProperty Name | Out-File C:\Temp\POSServers.txt
$servers = Get-Content C:\Temp\POSServers.txt
$servers | foreach {
$server = $_
$serverIP = Test-Connection -ComputerName $server -Count 1 | Select -ExpandProperty IPV4Address
$serverIPString = $serverIP.IPAddresstoString
$scope = Get-DhcpServerv4Scope -ComputerName $server
$options = Get-DhcpServerv4OptionValue -ComputerName $server
New-Object -TypeName psobject -Property #{
ServerName = $server
ServerIP = $serverIPString
ScopeName = $scope.Name | Out-String
StartIP = $scope.StartRange.IPAddressToString | Out-String
EndIP = $scope.EndRange.IPAddressToString | Out-String
SubnetMask = $scope.SubnetMask.IPAddressToString | Out-String
Duration = $scope.LeaseDuration.Days | Out-String
OptionName = $options.Name | Out-String
OptionID = $options.OptionID | Out-String
OptionValue = $options.Value | Out-String
}
for ($i = ($Options.Count -1); $i -gt -1; $i--) {
Add-Content -Value "$($server),$($serverIPString),$($scope.Name),$($scope.StartRange.IPAddressToString),$($scope.EndRange.IPAddressToString),$($scope.SubnetMask.IPAddressToString),$($scope.LeaseDuration.Days),$($options[$i].Name),$($options[$i].OptionID),$($Options[$i].Value)" -Path C:\temp\POSScopes.csv
}
}
Add-Content -Value "ServerName,ServerIP,ScopeName,StartRange,EndRange,SubnetMask,Duration,OptionName,OptionID,Value" -Path c:\temp\POSScopes.csv
Get-ADComputer -Filter {Name -like 'p****p01' -or Name -like 'p****p02' -or Name -like 'q****001' -or Name -like 'q****002'} | Sort-Object | Select -ExpandProperty Name | Out-File C:\Temp\POSServers.txt
$servers = Get-Content C:\Temp\POSServers.txt
$servers | foreach {
$server = $_
$serverIP = Test-Connection -ComputerName $server -Count 1 | Select -ExpandProperty IPV4Address
$serverIPString = $serverIP.IPAddresstoString
$scope = Get-DhcpServerv4Scope -ComputerName $server
$options = Get-DhcpServerv4OptionValue -ComputerName $server
New-Object -TypeName psobject -Property #{
ServerName = $server
ServerIP = $serverIPString
ScopeName = $scope.Name | Out-String
StartIP = $scope.StartRange.IPAddressToString | Out-String
EndIP = $scope.EndRange.IPAddressToString | Out-String
SubnetMask = $scope.SubnetMask.IPAddressToString | Out-String
Duration = $scope.LeaseDuration.Days | Out-String
OptionName = $options.Name | Out-String
OptionID = $options.OptionID | Out-String
OptionValue = $options.Value | Out-String
}
for ($i = ($Options.Count -1); $i -gt -1; $i--) {
Add-Content -Value "$($server),$($serverIPString),$($scope.Name),$($scope.StartRange.IPAddressToString),$($scope.EndRange.IPAddressToString),$($scope.SubnetMask.IPAddressToString),$($scope.LeaseDuration.Days),$($options[$i].Name),$($options[$i].OptionID),$($Options[$i].Value)" -Path C:\temp\POSScopes.csv
}
}
Objective: How to extract server information?
For each server name listed in servers.txt, I would like to get the following information (in this format):
Server name, IP Address, OS name, Total Physical Memory, Processors, each drive letter and size, System Model
Comma separated and new line for each server.
Below is my PowerShell code. Can your guys give a hint on why this does not work? Also why I get an error with New-Object statement?
foreach ($ComputerName in (Get-Content -Path .\servers.txt)) {
$HashProps = #{
'tHostname' = Get-WmiObject Win32_Computersystem -ComputerName $ComputerName | Select-Object -ExpandProperty Name
'tIP' = [System.Net.Dns]::GetHostAddresses($computername)
'tOS' = Get-WmiObject -ComputerName $ComputerName -Class Win32_OperatingSystem | Select-Object -ExpandProperty Caption
'tMemory' = Get-WmiObject Win32_PhysicalMemory | Measure-Object -Property capacity -Sum | foreach { "$("{0:n2}" -f ( $_.Sum/1GB ) )" }
'tcpu' = Get-WmiObject Win32_processor | Select-Object name, numberofcores
'tDisks' = Get-WmiObject Win32_LogicalDisk | foreach { "$($_.DeviceID) $("{0:n2}" -f ( $_.Size/ 1GB ) )" }
'tsysmodel' = Get-Wmiobject Win32_computersystem | Select-Object model
}
New-Object -TypeName psObject -Property $HashProps |
ConvertTo-Csv -NoTypeInformation | Out-File -Append .\output.csv
}
I am open for a other approach, if this is easier.
Have you verified that each of those lines actually return what you want?
I just threw this into the ISE and it works fine:
$f = gwmi win32_computersystem | select name,model,totalphysicalmemory
$hash = #{
'name' = $f.name
'model' = $f.model
'memory' = $("{0:n2}" -f ( $f.totalphysicalmemory/1GB ) )
}
New-Object -TypeName psobject -Property $hash | ConvertTo-Csv -NoTypeInformation | Out-File -Append .\test.csv
Also, if you want the properties to appear in a specific order in the CSV, it will take some additional magic, otherwise they're put in alphabetically.
A little bit pimped, maybe this will help you:
$Servers = Foreach ($ComputerName in (Get-Content -Path .\Servers.txt)) {
$CS = Get-WmiObject Win32_ComputerSystem -ComputerName $ComputerName
$OS = Get-WmiObject Win32_OperatingSystem -ComputerName $ComputerName
$PM = Get-WmiObject Win32_PhysicalMemory -ComputerName $ComputerName
$PR = Get-WmiObject Win32_processor -ComputerName $ComputerName
$LD = Get-WmiObject Win32_LogicalDisk -ComputerName $ComputerName
$IP = [System.Net.Dns]::GetHostAddresses($ComputerName)
[PSCustomObject]#{
ServerName = $CS | Select-Object -ExpandProperty Name
IPAddress = $IP | Select-Object -ExpandProperty IPAddressToString
OS = $OS | Select-Object -ExpandProperty Caption
Memory = $PM | Measure-Object -Property Capacity -Sum | foreach { "$("{0:n2}" -f ( $_.Sum/1GB ) )" }
CPU = $PR | Select-Object Name, NumberOfCores
Disks = $LD | foreach { "$($_.DeviceID) $("{0:n2}" -f ( $_.Size/ 1GB ) )" }
Model = $CS | Select-Object -ExpandProperty Model
}
}
$File = Join-Path $env:TEMP 'Ouptut.csv'
$Servers | Export-Csv -Path $File -NoTypeInformation -Delimiter ';'
Start-Process $File
I'm sure there is a simple solution, but I'm stuck. The output in the members column is like this
{domain\Domain Admins, domain\joerod...
How can I show the
$member
value on each line?
Function Get-AdminGroups{
foreach($i in (Get-Content C:\Users\joerod\Desktop\remove_users.txt)){
#test if machine is on the network
if (-not (Test-Connection -computername $i -count 1 -Quiet -ErrorAction SilentlyContinue)) {
Write-Warning "$i is Unavalible"
"`r"
}
else {
(invoke-command {
$members = net localgroup administrators |
? {$_ -AND $_ -notmatch "command completed successfully"} |
select -skip 4
New-Object PSObject -Property #{
Computername = $env:COMPUTERNAME
Users=$members
}
} -computer $i -HideComputerName |
Select * -ExcludeProperty RunspaceID )
}
}
}
Get-AdminGroups |ft
Iterate through $members and make an object for each one. This creates an empty array, loops through the computers in your text file, and in that loop it pulls a list of the local administrators, and for each one it creates a custom object just like you are doing, and it adds it to that array.
$Results = #()
foreach($i in (GC C:\Users\joerod\Desktop\remove_users.txt)){
#test if machine is on the network
if (!(Test-Connection -computername $i -count 1 -Quiet -ErrorAction SilentlyContinue)) {
Write-Warning "$i is Unavalible`r"
Continue
}
invoke-command {
$members = net localgroup administrators |?{$_ -AND $_ -notmatch "command completed successfully"} | select -skip 4
ForEach($member in $members){
$Results += New-Object PSObject -Property #{
Computername = $env:COMPUTERNAME
Users=$member
}
}
} -computer $i -HideComputerName # | Select * -ExcludeProperty RunspaceID
}
$Results | FT