Switching code around in Powershell - powershell

I'm new to powershell and have been experimenting with code I found online. The following code is part of a script to find network info on a remote computer.
$NETS = Get-WMIObject -Class Win32_NetworkAdapterConfiguration -Filter "IPEnabled='True'" -ComputerName $First | Select DNSHostName, #{Name="IPAddress";Expression={$_.IPAddress[0]}},
#{Name="IPSubnet";Expression={$_.IPSubnet[0]}}, #{Name="DefaultIPGateway";Expression={$_.DefaultIPGateway[0]}}, DHCPEnabled
It works fine, but I also want to get the serial number for the PC as well, so I use this
$SN = Get-WMIObject win32_bios -ComputerName $First | Format-List SerialNumber
$NETS | Add-Member -MemberType NoteProperty -Name SN -Value $SN.SerialNumber -Force
This works as well, but what I want is to flip them. I want to get the serial number first and then append all the network info. I have very little understanding of powershell though so I am unclear as to how to do this.
Thanks.

You can query the SN in a calculated property as well:
$NETS = Get-WMIObject -Class Win32_NetworkAdapterConfiguration -Filter "IPEnabled='True'" -ComputerName $First
$NETS = $NETS |Select DNSHostName,
#{Name='SN';Expression={ (Get-WMIObject win32_bios -ComputerName $First).SerialNumber}},
#{Name="IPAddress";Expression={$_.IPAddress[0]}},
#{Name="IPSubnet";Expression={$_.IPSubnet[0]}},
#{Name="DefaultIPGateway";Expression={$_.DefaultIPGateway[0]}}, DHCPEnabled

Related

Get Uptime on Each Computer in an Array, Select the machines with the most uptime, and remotely execute a Script on each Machine

The majority of this code was pulled from a blog online, but I think it's exactly the way I need to be tackling this. I want to get the top 4 machines from an OU based on uptime, and run a script that lives on each of the top 4 machines. I know that the problem involves the Array losing access to the Get-ADComputer properties, but I'm unsure of how to pass these new properties back to their original objects. This works as expected until it gets to the foreach loop at the end.
$scriptBlock={
$wmi = Get-WmiObject -Class Win32_OperatingSystem
($wmi.ConvertToDateTime($wmi.LocalDateTime) – $wmi.ConvertToDateTime($wmi.LastBootUpTime)).TotalHours
}
$UpTime = #()
Get-ADComputer -Filter 'ObjectClass -eq "Computer"' -SearchBase "OU=***,OU=***,OU=***,DC=***,DC=***" -SearchScope Subtree `
| ForEach-Object { $Uptime += `
(New-Object psobject -Property #{
"ComputerName" = $_.DNSHostName
"UpTimeHours" = (Invoke-Command -ComputerName $_.DNSHostName -ScriptBlock $scriptBlock)
}
)
}
$UpTime | Where-Object {$_.UpTimeHours -ne ""} | sort-object -property #{Expression="UpTimeHours";Descending=$true} | `
Select-Object -Property ComputerName,#{Name="UpTimeHours"; Expression = {$_.UpTimeHours.ToString("#.##")}} | Select-Object -First 4 |`
Format-Table -AutoSize -OutVariable $Top4.ToString()
foreach ($Server in $Top4.ComputerName) {
Invoke-Command -ComputerName $Server -ScriptBlock {HOSTNAME.EXE}
}
I'm not married to Invoke-Command in the last foreach but am having the same issues when I try to use psexec. Also, I'm running hostname.exe as a check to make sure I'm looping through the correct machines before I point it at my script.
Here's a streamlined version of your code, which heeds the comments on the question:
# Get all computers of interest.
$computers = Get-ADComputer -Filter 'ObjectClass -eq "Computer"' -SearchBase "OU=***,OU=***,OU=***,DC=***,DC=***" -SearchScope Subtree
# Get the computers' up-times in hours.
# The result will be [double] instances, but they're also decorated
# with .PSComputerName properties to identify the computer of origin.
$upTimes = Invoke-Command -ComputerName $computers.ConputerName {
((Get-Date) - (Get-CimInstance -Class Win32_OperatingSystem).LastBootUpTime).TotalHours
}
# Get the top 4 computers by up-time.
$top4 = $upTimes | Sort-Object -Descending | Select-Object -First 4
# Invoke a command on all these 4 computers in parallel.
Invoke-Command -ComputerName $top4.PSComputerName -ScriptBlock { HOSTNAME.EXE }

Trying to capture IP from powershell script, getting System.String[] instead

I'm trying to pull a machine's IPAddress, MACAddress, and DefaultIPGateway information from the Win32_NetworkAdapterConfiguration object into an exported CSV file named NetworkAdapterConfiguration.csv using this script:
$StrComputer = $env:computername
$NetAdConfig = gwmi Win32_NetworkAdapterConfiguration -Comp $StrComputer
$NetAdConfig | Select-Object IPAddress,MACAddress,DefaultIPGateway | Export-Csv -Path C:\CSVFolder\NetworkAdapterConfiguration.csv -Encoding ascii -NoTypeInformation
When I view this CSV I get "System.String[]" where the IP and DefaultIPGateway values should be displayed. I'm assuming this information gets represented as an array and that is why I'm seeing the System.String[] view, but I have little experience with Powershell. Any help, advice, and references are much appreciated.
The IPAddress and DefaultIPGateway properties are arrays. If you are sure your machines only have one IP address and default gateway, you can do this:
$computer = $ENV:COMPUTERNAME
get-wmiobject Win32_NetworkAdapterConfiguration -filter "IPEnabled=TRUE" -computername $computer | foreach-object {
new-object PSObject -property #{
"Computer" = $computer
"MACAddress" = $_.MACAddress
"IPAddress" = $_.IPAddress[0]
"DefaultIPGateway" = $_.DefaultIPGateway[0]
} | select-object Computer,MACAddress,IPAddress,DefaultIPGateway
}
Here's another way that uses Select-Object:
$computer = $ENV:COMPUTERNAME
get-wmiobject Win32_NetworkAdapterConfiguration -filter "IPEnabled=TRUE" -computername $computer | foreach-object {
$_ | select-object `
#{Name="ComputerName"; Expression={$_.__SERVER}},
#{Name="MACAddress"; Expression={$_.MACAddress}},
#{Name="IPAddress"; Expression={$_.IPAddress[0]}},
#{Name="DefaultIPGateway"; Expression={$_.DefaultIPGateway[0]}}
}
I have a function that I wrote called Convert-OutputForCSV that can help to remove the string[] issues you are seeing as well. You could do something like this to expand out the arrays into a more readable property.
$StrComputer = $env:computername
$NetAdConfig = gwmi Win32_NetworkAdapterConfiguration -Comp $StrComputer
$NetAdConfig | Select-Object IPAddress,MACAddress,DefaultIPGateway |
Convert-OutputForCSV |
Export-Csv -Path C:\CSVFolder\NetworkAdapterConfiguration.csv -Encoding ascii -NoTypeInformation

Include computername parameter with Get-WmiObject data

Using PowerShell, I want to include the computer name with some of the returned data of the WMI query. I've studied custom columns - need something like that - but I do not know how to pass the computer name into the next loop to be included in the resulting table. For example:
Get-WmiObject -Class Win32_LogicalDisk -ComputerName MailServer01
Actually, I'm in another look where $_ is the computer name:
Get-WmiObject -Class Win32_LogicalDisk -ComputerName $_
This works great, but I want to include the ComputerName ($_) as part of the final output or report. Any ideas?
The computername is already there (as SystemName). It just isn't part of the default display properties.
Run
Get-WmiObject -Class Win32_LogicalDisk -ComputerName MailServer01 | format-list *
to see all of the properties of the returned objects.
The "__Server" property will always be available for the get-wmiobject objects
Also note:
"Beginning in Windows PowerShell 3.0, the __Server property of the object that Get-WmiObject returns has a PSComputerName alias. This makes it easier to include the source computer name in output and reports."
http://technet.microsoft.com/en-us/library/hh849824.aspx
Try this
Get-WMiObject -Class Win32_LogicalDisk -ComputerName $_ | Add-Member -MemberType NoteProperty -Name ComputerName -Value $_ -PassThru
Then you can output or manipulate your data anyway you see fit, and the properties you add via Add-Member will be available on that object as long as it exists.
Docs for the cmdlet are here
Yeah, I didn't realize there were more properties. Works great: __Server was the property I needed:
$myServers = #("server1", "server2", "server3")
"" > space.txt
$myServers | foreach-object {
write-host "Server: $_"
Get-WmiObject -Class Win32_LogicalDisk -ComputerName $_ | ? { $_.DeviceID -notmatch " [AR]"} | Select -Property __Server, DeviceID, #{Name=’FreeSpaceMB’;Expression={$_.FreeSpace/1MB} } | Format-Table -AutoSize >> c:\space.txt
}

PowerShell - Select-Object from Win32_OperatingSystem displays rather oddly

First time poster here, I'm a bit of a beginner and I've been keen to get my PowerShell scripting skills up to scratch and I'm come across something rather confusing...
I've made a script to query a collection of computers and I want to query Win32_OperatingSystem but only extrapolate the Build number so I can populate my PSObject with it. I'm trying to add some If logic so that if the build number is 7601, I can write a message under my OS column.
The problem I'm having is that the BuildNumber values are coming out as #{BuildNumber=7601} instead of 7601 for instance. That, and my If statement is borked.
$Machines = Get-Content .\Computers.txt
Foreach($Machine in $Machines)
{
$sweet = (Get-WmiObject -Class Win32_OperatingSystem -computer $Machine | Select-Object BuildNumber)
$dversion = if ($sweet -eq "#{BuildNumber=7601}") {Yes!} else {"Nooooo!"}
New-Object PSObject -Property #{
ComputerName = $Machine
Sweet = $sweet
OS = $dversion
}
}
The issue is that the Get-WMIObject cmdlet is returning a Hash Table. Then the Select-Object is returning just the BuildNumber section you want, the BuildNumber property and it's value. You need to add the -ExpandProperty parameter to only get the value back, not the name/value pair.
Get-WMIObject -Class Win32_OperatingSystem | Select-Object BuildNumber
Returns
#{BuildNumber=7601}
With ExpandProperty
Get-WMIObject -Class Win32_OperatingSystem | Select-Object -ExpandProperty BuildNumber
Returns
7601
Just another option with a ping test to skip unavailable machines.
Get-Content .\Computers.txt | Where-Object {Test-Connection -ComputerName $_ -Count 1 -Quiet} | Foreach-Object {
$sweet = Get-WmiObject -Class Win32_OperatingSystem -ComputerName $_ | Select-Object -ExpandProperty BuildNumber
New-Object PSObject -Property #{
ComputerName = $_.__SERVER
Sweet = $sweet
OS = if ($sweet -eq 7601) {'Yes!'} else {'Nooooo!'}
}
}

Querying partitions/drives on a remote server with WMI

I do the following to check for local drives/partitions on a remote computer:
Get-WmiObject -Class Win32_Share -ComputerName SERVERNAME -Filter "Description='Default share'"
but the command also returns CD-roms etc.
Is there a command to only return disk/partitions?
Get-WmiObject -Class Win32_LogicalDisk -Filter "DriveType=3" |
Foreach-Object {$_.DeviceID}
Try this:
Get-WMIObject Win32_DiskPartition -computername remotecomp |
ForEach-Object {
$info = #{}
$info.Disk = $_.DiskIndex
$info.Partition = $_.Index
$info.DriveLetter = $_.psbase.GetRelated('Win32_LogicalDisk') |
Select-Object -ExpandProperty DeviceID
New-Object PSObject -Property $info
}
$info # contains partions number and unit letter as hashtable
Get-WmiObject -query "Select * from Win32_DiskPartition" ... maybe?