Failing to find DC servers and their disk usage - windows

so i got stuck with this assignment where i need to find all DC servers and their disk ussage
i tried first to get all the DC servers and then add the disk usage info but it doesn't work
$getdomain = [System.Directoryservices.Activedirectory.Domain]::GetCurrentDomain()
$getdomain | ForEach-Object {$_.DomainControllers} |
ForEach-Object {
$hEntry= [System.Net.Dns]::GetHostByName($_.Name)
New-Object -TypeName PSObject -Property #{
Name = $_.Name
IPAddress = $hEntry.AddressList[0].IPAddressToString
}
} | get-wmiobject -class win32_logicaldisk | select-object pscomputername,deviceid,freespace,size

For the task you have you have some useless code lines in your code. Did you copy the code from somewhere? ;-)
I'd recommend to take your time to start learning the very basics of Powershell first.
That's actually all you need:
$DCList = [System.Directoryservices.Activedirectory.Domain]::GetCurrentDomain().DomainControllers
foreach ($DC in $DCList) {
Get-CimInstance -ClassName win32_logicaldisk -ComputerName $DC.Name |
Select-Object -Property pscomputername, deviceid, freespace, size
}
Conclusion: You should remove what you have inside the loop from your copied code and replace it with what you have added at the end. ;-)

Related

Listed highest CPU usage windows

I can get list the processes but how would I get them to show by highest usage instead of alphabetically?
Wmic path win32_performatteddata_perfproc_process get Name,PercentProcessorTime
From powershell you don't need to make direct calls to wmic, Get-CimInstance is meant to easily query all instances of WMI and CIM classes and output objects which are easy to manipulate. Sorting objects in PowerShell can be done with Sort-Object.
Get-CimInstance Win32_PerfFormattedData_PerfProc_Process |
Sort-Object PercentPrivilegedTime -Descending |
Select-Object Name, PercentProcessorTime
You could even go one step further and group the objects by their name with the help of Group-Object:
Get-CimInstance Win32_PerfFormattedData_PerfProc_Process |
Group-Object { $_.Name -replace '#\d+$' } | ForEach-Object {
[pscustomobject]#{
Instances = $_.Count
Name = $_.Name
PercentProcessorTime = [Linq.Enumerable]::Sum([int[]] $_.Group.PercentProcessorTime)
}
} | Sort-Object PercentProcessorTime -Descending

Have I written this PowerShell script well enough to balance simplicity and performance?

I have a script that checks remote servers for tomcat and the associated java versions. It takes about 60 seconds to run against a list of about 16 servers. I'm just curious if the script is as efficient as realistically possible. I'm far from a PowerShell pro but I'm satisfied with the outcome. Just checking for where there is room for improvement.
$Servers = 'server1','server2','etc'
$Output = #()
foreach ($Server in $Servers)
{
$SName = gwmi -Class Win32_Service -ComputerName $Server -Filter {Name LIKE 'Tomcat%'}
IF ($SName -ne $null) {
$Output += [PSCustomObject]#{
Server_name = $SName.PSComputerName
Service_name = $SName.Name
Service_status = $SName.State
Tomcat_version = "$(Get-Content -Path ("\\"+$SName.PSComputerName+"\"+"$($SName.PathName.ToString())".Substring(0,$SName.Pathname.LastIndexOf("\")-3)+"\webapps\ROOT\RELEASE-NOTES.txt" -replace ":", "$") | Select-String -Pattern 'Apache Tomcat Version ')".TrimStart()
Java_Version = (Invoke-Command -ComputerName $Server -ScriptBlock {(GCI -Path "$((Get-ItemProperty -Path 'HKLM:\SOFTWARE\WOW6432Node\Apache Software Foundation\Procrun 2.0\Tomcat9\Parameters\Java').Jvm)").VersionInfo.ProductName})
}
}
Else {}
}
$Output | Select Server_name, Service_name,Service_status, Tomcat_Version, Java_Version | Format-Table -AutoSize
Can I simplify things anymore?
Is the time to completion decent for what is being performed?
Invoke-Command allows you to connect with multiple computers at the same time which should be more efficient.
+= is pretty bad, please read: Why should I avoid using the increase assignment operator (+=) to create a collection
You're querying WMI first and then if service is there you are using Invoke-Command, mind as well, connect once to the remote host and check everything.
I personally would do something like this
$Servers = 'server1','server2','etc'
$scriptBlock = {
# Since you're querying each server, and then if the service is there you Invoke-Command,
# mind as well Invoke-Command at first and if the service is there enter the If condition,
# else close the connection.
$tomcatServ = Get-CimInstance -Class Win32_Service -Filter "Name LIKE 'Tomcat%'"
if($tomcatServ)
{
##### This part is pretty confusing for someone reading your code, if you show us how does
##### RELEASE-NOTES.txt looks we may be able to improve it and simplified it a bit
$path = $tomcatServ.PathName.Substring(0,$tomcatServ.PathName.LastIndexOf("\")-3)
$path = Join-Path $path -ChildPath "webapps\ROOT\RELEASE-NOTES.txt"
$tomCatVer = ((Get-Content $path) -replace ":", "$" | Select-String -Pattern 'Apache Tomcat Version ').TrimStart()
##### This part is a bit confusing too
$key = 'HKLM:\SOFTWARE\WOW6432Node\Apache Software Foundation\Procrun 2.0\Tomcat9\Parameters\Java'
$javaVer = GetChild-Item -Path ((Get-ItemProperty -Path $key).Jvm).VersionInfo.ProductName
#####
[PSCustomObject]#{
Server_name = $env:ComputerName
Service_name = $tomcatServ.Name
Service_status = $tomcatServ.State
Tomcat_version = $tomCatVer
Java_Version = $javaVer
}
}
}
$Output = Invoke-Command -ComputerName $Servers -ScriptBlock $scriptBlock -HideComputerName
$Output | Select-Object * -ExcludeProperty RunspaceID | Format-Table -AutoSize

Matching two lists and find uninstall string with Powershell

I have a problem with my Script.
I wanted to make a Script which makes a list of software which is found in a specific registry path
and see if this software equals installed software. and if so it should output me the uninstall string.
but right now it does not work as wanted. it never show me the output I wanted even if its similar. As Example i have the Program Git as Branding and in the software I got Git version 2.26.2 but it wont output the uninstall string when I selected git.
My code is:
$branding = Get-ChildItem "HKLM:\Software\DLR\Branding" | Get-ItemProperty | Select-Object -expandProperty ProgramName
$software = Get-ChildItem -Path HKLM:\SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall, HKLM:\SOFTWARE\Wow6432Node\Microsoft\Windows\CurrentVersion\Uninstall | Get-ItemProperty | Select-Object -ExpandProperty DisplayName
ForEach ($brandinglist in $branding) {
$objCombobox.Items.Add("$brandinglist")
}
$objComboBox_SelectedIndexChanged=
{
$selectme = $objCombobox.SelectedItem
Write-Host $selectme
if ("$selectme" -like "*$software*") {
$uninstall = Get-ChildItem -Path HKLM:\SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall, HKLM:\SOFTWARE\Wow6432Node\Microsoft\Windows\CurrentVersion\Uninstall | Get-ItemProperty | Where-Object {$_.DisplayName -match "$electme" } | Select-Object -Property UninstallString
Write-Host "$uninstall"
}
}
You are trying the -like comparison wrong, in which you compare the selected item to an array of displaynames which doesn't work that way.
Also, there is no reason to get the Uninstall strings and Displaynames using an almost identical code twice.
Try
# get a string array of program names
$branding = Get-ChildItem -Path 'HKLM:\Software\DLR\Branding' | Get-ItemProperty | Select-Object -ExpandProperty ProgramName
$regPaths = 'HKLM:\SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall', 'HKLM:\SOFTWARE\Wow6432Node\Microsoft\Windows\CurrentVersion\Uninstall'
# get an object array of DisplayName and UninstallStrings
$software = Get-ChildItem -Path $regPaths | Get-ItemProperty | Select-Object DisplayName, UninstallString
# fill the combobox with the (string array) $branding
$objCombobox.Items.AddRange($branding)
$objComboBox.Add_SelectedIndexChanged ({
$selectme = $objCombobox.SelectedItem
Write-Host $selectme
# get the objects that have a displayname like the selected item and write out the matching Uninstall strings
$software | Where-Object {$_.DisplayName -like "*$selectme*" } | ForEach-Object {
Write-Host $_.UninstallString
}
})

How to get every disk in Windows and filter on DeviceType and then add the size of the disk next to it, separated by a comma?

I'm writing an PowerShell script to collect some data of a computer. I'm almost done, but I don't know how to get size of all the disks on the computer. I know how to do it with a couple of If statements, but I want it to automatically detect the drives, not that I have to write a new If statement if a new disk is attached. The output I want is as follows: "A:,250GB". The "A:," bit works, but not the disk size bit.
This is the code I used and tweaked, but to no avail:
$Drives = Get-WmiObject Win32_logicaldisk| ?{$_.DriveType -eq 3} | ForEach-Object {$_.name}
ForEach ($Drivename in $Drives) {
$Drivenames = Get-WMIObject -Query "Select * From win32_logicaldisk Where DriveType = '3'" -computer localhost | Select-Object DeviceID
$Drive = [Math]::Round($Drivenames.Size / 1GB)
"$Drivenames,", $Drive | Out-File "C:\HDS\HDS_DRIVES.csv" -Append
}
In addition, [Math]::Round($Drivenames.Size / 1GB) throws me an error:
Method invocation failed because [System.Object[]] does not contain a method named 'op_Division'"
You can use Calculated Property with Select-Object to make it much more simple:
Get-WmiObject Win32_logicaldisk| ? {$_.DriveType -eq 3} |
Select-Object #{N="DeviceId";E={$_.DeviceId}},`
#{N="VolumeName";E={$_.VolumeName}},`
#{N="Size";E={[Math]::Round($_.Size / 1GB)}} |
Out-File "C:\HDS\HDS_DRIVES.csv" -Append
Note that you don't need to Invoke Get-WmiObject Twice like in your example.
Why it doesn't work?
The issue is that $Drivenames contains only DeviceID (as you used Select-Object to get only that property). Therefore you're getting an error where trying to round it (as rounding nothing is not supposed to work).
How to fix it?
You have to add Size and then access it using .PropertyName:
$DriveInfo = Get-WMIObject -Query "Select * From win32_logicaldisk Where DriveType = '3'" -computer localhost | Select-Object DeviceID, Size
$DriveInfo | ForEach-Object {
$DriveSize = [Math]::Round($_.Size / 1GB)
"$($_.DeviceID),$DriveSize" | Out-File "C:\HDS\HDS_DRIVES.csv" -Append
}
How can I make it more elegant
Also, take a look at #Avshalom's answer which uses calculated property.

Obtain a list of non-admin file shares from multiple Windows servers

GOAL: Obtain a CSV file with the following information:
Computer Name
Share Name
Share Path
Share Description
for all non-admin (type 0) SMB shares on all servers from a list (txt file).
INITIAL CODE:
param (
[Parameter(Mandatory=$true,Position=0)]
[ValidateNotNullOrEmpty()]
[String]
$path
)
$computers = Get-Content $path
$shareInfo = #()
ForEach ($computer in $computers) {
$shares = gwmi -Computer $computer -Class Win32_Share -filter "Type = 0" | Select Name,Path,Description
$shares | % {
$ShareName = $_.Name
$Props = [ordered]#{
Computer = $computer
ShareName = $_.Name
Path = $shares.Path
Description = $shares.Description
}
}
$ShareInfo += New-Object -TypeName PSObject -Property $Props
}
$shareInfo | Export-CSV -Path .\shares.csv -NoType
CODE OUTPUT:
"Computer","ShareName","Path","Description"
"SERVER1","SHARE1","System.Object[]","System.Object[]"
"SERVER2","SHARE12","System.Object[]","System.Object[]"
"SERVER3","SHARE3","System.Object[]","System.Object[]"
PROBLEM:
While the code provides output for each server, it seems to not include all shares from the servers. Furthermore, the Path and Description fields are not populated with good information.
ADDITIONAL INFO:
The code:
$shares = gwmi -Computer $computer -Class Win32_Share -filter "Type = 0" | Select Name,Path,Description
Produces good information as below:
Name Path Description
---- ---- -----------
print$ C:\WINDOWS\system32\spool\drivers Printer Drivers
Share D:\Share
SHARE2 D:\SHARE2
Software C:\Software The Software
$shares | % {
$ShareName = $_.Name
$Props = [ordered]#{
Computer = $computer
ShareName = $_.Name
Path = $shares.Path
Description = $shares.Description
}
}
You're using $shares instead of $_ for the Path and Description properties, so each of these properties is assigned a list of the values of the respective property of each element of the $shares collection.
Also, why are you building custom objects in the first place when you just need to filter the WMI query results? The computer name can be obtained from the __SERVER (or PSMachineName) property. Plus, type 0 means a shared disk drive, not an administrative share. You need to filter the latter by other criteria (usually description and/or share name).
$filter = "Type = 0 And Description != 'Default Share' And " +
"Name != 'ADMIN$' And Name != 'IPC$'"
$computers |
ForEach-Object { Get-WmiObject -Computer $_ -Class Win32_Share -Filter $filter } |
Select-Object #{n='Computer';e={$_.__SERVER}}, Name, Path, Description |
Export-Csv -Path .\shares.csv -NoType

Resources