Using PoSH to get a value, strange results - powershell

I am using PoSH to query our Exchange server to return the largest mailbox by users.
My PoSH is:
$test = Get-MailboxDatabase MBX_* -Status | select Name,#{Name="NumberofUsers";Expression={(Get-Mailbox -resultsize unlimited -Database $_.name).Count}} | Sort -Property NumberofUsers | Select Name -First 1
This works in console and returns:
Name
----
MBX_2
However when I run it like this in a script and return the value, it is like this:
$test = Get-MailboxDatabase -Status MBX_*| select Name,#{Name="NumberofUsers";Expression={(Get-Mailbox -resultsize unlimited -Database $_.name).Count}} | Sort -Property NumberofUsers | Select Name -First 1
Write-Host "Using $test"
Using #<Name=MBX_2>
Why is it including the #<Name=> characters and how can I prevent it from doing that? I need to be able to grab just the returned value of "MBX_2" for the next part of my script and I am confused on how to go about this...

You are selecting a single property of the object, but still passing an object. What you need to do is use the -ExpandProperty parameter of the Select-Object cmdlet. Change your Select command to this:
| Select -ExpandProperty Name -First 1
That should give you the results that you desire.

Related

Task Manager thread counts and username query

I'm new to working with powershell and I'm trying to create a script where I can check a remote machines specific process thread counts along with the username and in the output I hope I can get the highest thread user.
I'm started from this script as a reference but I can't seen to find the right commands/syntax
Get-Process | Select-Object Name, #{Name='ThreadCount';Expression ={$_.Threads.Count}} | Sort-Object -Property Threadcount -Descending
Get-Process have an optional -IncludeUserName switch argument you can include to get the username out of the command. It will requires admin. priviledge to collect that information.
Once you have the information, you will need to group by user and then sort by the sum of threads per user to get your desired "Highest thread users".
Here is what that would look like.
#requires -runasadministrator
$ProcessesSummary = Get-Process -IncludeUserName |
Select-Object Name, #{Name = 'ThreadCount'; Expression = { $_.Threads.Count } },Username
$ProcessesSummary |
Group-Object -Property Username |
Select Name,#{N='TotalThreads';E={($_.Group.ThreadCount |
Note that if you do not do anaything with $ProcessesSummary other than using it for the total thread per user, you can forego the first statement completely and instead just do
#requires -runasadministrator
Get-Process -IncludeUserName |
Group-Object -Property Username |
Select Name,#{N='TotalThreads';E={($_.Group.Threads.Count | Measure-Object -Sum).Sum}} |
Sort TotalThreads -Descending |
Where Name -NotLike 'NT*' # If you want to remove some of the system accounts from the output

Sorting Office 365 user account / mailbox properties

I'm accessing my cloud Office 365 Exchange Server via Powershell. Showing all properties of an account can be done via Get-Mailbox 'username' | Select * (MS reference).
On most systems those properties are already sorted (e.g. Get-ADUser 'username' -Properties *). Is it possible to sort the Get-Mailbox output? I thought Get-Mailbox 'username' | Select * | Sort-Object would do the trick but it didn't make any difference (I guess a property doesn't constitute an object). What's the right command to sort the properties for a single user?
Note: Sorting properties of multiple accounts works fine e.g. Get-Mailbox -filter * | select Name, DisplayName | Sort-Object Displayname
Update:
I managed to get a sorted properties list using
(Get-Mailbox 'mailboxname' | select *).PSObject.properties | ForEach-Object {$_.Name} | Sort-Object Name
it gets me the following output:
AcceptMessagesOnlyFrom
AccountDisabled
AddressBookPolicy
ArchiveWarningQuota
...
$_.Name gives me the values but so far I couldn't combine both into one list, I'm trying to get s.th. like this:
AcceptMessagesOnlyFrom = {}
AccountDisabled = False
AddressBookPolicy =
ArchiveWarningQuota = 45 GB (48,318,382,080 bytes)
...
I'm not completely sure this is what you are after, let me know if I'm wrong. As in my comment, Sort-Object can handle sorting a list or an object[] by one or more of it's properties; but sorting one single object by it's properties, say alphabetically, would require a combination of accessing the object's properties with .PSObject.Properties.Name and then sorting this list with Sort-Object. And after that we can use Select-Object with this sorted list to display the object as we want.
Using the object below as an example as I have no idea how of the type Microsoft.Exchange.Data.Directory.Management.Mailbox looks.
$mailbox = [pscustomobject]#{
DisplayName = 'someuser'
UserPrincipalName = 'someuser#somedomain.com'
Mail = 'someuser#somedomain.com'
IsLicensed = $true
}
$properties = $mailbox.PSObject.Properties.Name | Sort-Object
$mailbox | Select-Object $properties
As you can see, object's properties are now sorted alphabetically:
DisplayName IsLicensed Mail UserPrincipalName
----------- ---------- ---- -----------------
someuser True someuser#somedomain.com someuser#somedomain.com
By looking at your edit, seems like you are looking for a one-liner, so this is how it could look:
Get-Mailbox 'mailboxname' | ForEach-Object {
$_ | Select-Object ($_.PSObject.Properties.Name | Sort-Object)
}

How to strip out everything but numbers in a variable?

I'm trying to automate setting an IP address through PowerShell and I need to find out what my interfaceindex number is.
What I have worked out is this:
$x = ( Get-NetAdapter |
Select-Object -Property InterfceName,InterfaceIndex |
Select-Object -First 1 |
Select-Object -Property Interfaceindex ) | Out-String
This will output:
InterfaceIndex
--------------
3
Now the problem, when I try to grab only the number using:
$x.Trim.( '[^0-9]' )
it still leave the "InterfaceIndex" and the underscores. This causes the next part of my script to error because I just need the number.
Any suggestions?
This will get your job done:
( Get-NetAdapter | Select-Object -Property InterfceName,InterfaceIndex | Select-Object -First 1 | Select-Object -Property Interfaceindex).Interfaceindex
Actually you do not need two times to select the property: do like this:
( Get-NetAdapter |Select-Object -First 1| Select-Object -Property InterfceName,InterfaceIndex).Interfaceindex
Answering your immediate question: you can remove everything that isn't a number from a variable by, well, removing everything that isn't a number (or rather digit):
$x = $x -replace '\D'
However, a better aproach would be to simply not add what you want removed in the first place:
$x = Get-NetAdapter | Select-Object -First 1 -Expand InterfaceIndex
PowerShell cmdlets usually produce objects as output, so instead of mangling these objects into string form and cutting away excess material you normally just expand the value of the particular property you're interested in.
(Get-NetAdapter | select -f 1).Interfaceindex
No point in selecting properties as they are there by default. If you want to keep object do:
(Get-NetAdapter | select -f 1 -ov 'variablename').Interfaceindex
where f = first, ov = outvariable
$variablename.Interfaceindex
You don't need Out-String as cast to string is implicit when you output to screen. and if you try to work with this data further down powershell is clever enough to cast it from int to string and vice versa when needed.

Powershell Array to export-csv shows System.Object[]

Having a simple issue that's only affecting export-csv output, out-gridview and results to the console are fine. Looking to capture the top 5 processes by "handles" on a set of servers.
Code is as follows:
$Servers = "Server1", "Server2", "Server3"
$OutArray = #()
ForEach ($Item in $Servers)
$Top5 = Get-Process -Computer $Item | Sort Handles -descending |Select -First 5
$OutArray += New-Object PSObject -property # {
Server = $Item
Top5 = $Top5
} #OutArray
} #ForEach
$OutArray | Export-csv Test.csv
The results of which come out looking fine via console as follows
Server Top5
------ ----
SERVER1 {#{ProcessName=svchost.exe; PercentCpuLoad=13.79}, #{ProcessName=services.exe; PercentCpuLoad=11.4}, #{ProcessName=WmiPrvSE.exe; PercentCpuLoad=10.03}, #{ProcessName=irfilcol.exe; PercentCpuLoad=9.79}...}
...However, in the csv they show as follows:
Server Top5
Server1 System.Object[]
Server2 System.Object[]
Server3 System.Object[]
I'm thinking it's because the $Top5 variable is an variable with multiple properties (5 each) for one server. How would do I correct the code so that export-csv shows the actual values?
any help appreciated!
I would like the csv results to look like the following that's shown in GRIDVIEW
Using the suggestion from BenH to review the post from Powershell legend Boe Prox, I now have the following working:
$Top5 = Get-Process -Computer $Item | Sort Handles -descending |Select -expand Handles | |Select -First 5
$new = [pscustomobject]#{ Top5 = (#($Top5) -join ',')
}
Just about got this working now:
i'd like to add more piece of formatting, where the Top5Processes have the actual CPU % used in (brackets) right now, I've got the following for output
Top2Proc Top2CPU
services.exe,BESClient.exe 32.76,16.6
However, it would be nicer output-wise, if i could combine the above two values into one, so it looks like this:
Top2Proc
Services(32.76), BesClient.exe(16.6)
Any idea how that would be done?
Use Select-Object to turn your process objects into strings before piping them to Export-Csv:
$OutArray |Select-Object Server,#{Expression={$_.Top5.Name -join ';'}} |Export-Csv test.csv
If you want that table to appear in your csv file then you would need to format the string Top5 property as such. Using Out-String will do just that
Sends objects to the host as a series of strings.
So a simple change should get you what you want.
$Top5 = Get-Process -Computer $Item |
Sort Handles -descending |
Select -First 5 |
Out-String
It will look a little ugly when not displayed with a mono-space font much like you see in Out-GridView. Also consider using .Trim() to remove the leading and trailing whitespace on your $top5.
There are other ways to tackle this. You could use the above in conjunction with Format-Table / Format-List depending what you want. In general if you want the output to be saved as it is displayed in host Out-String is something to test with.
I would have tried to add one row for each process with a the first column being the computer name. That way you would have better structured output that can be sorted or queried as needed.
ComputerName ProcessName Handles
------------ ----------- -------
Computer1 avp 54639
Computer1 OUTLOOK 7708
Computer1 RDTabs 6108
Computer1 svchost 3160
Computer1 chrome 2530
Keep in mind that you can use other methods to export this data while keeping the objects entact. Really depends the data recipeint but remeber there are other cmdlets like Export-CLIMXL and ConvertTo-JSON | Set-Content.

how to get exact user name from get-mobiledevicestatistics in powershell

I have a small script to get all user mobile devices info from exchange 2013 server.
Get-Mailbox -ResultSize Unlimited |
ForEach {Get-MobileDeviceStatistics -Mailbox:$_.Identity} |
Select-Object #{label="User" ; expression={$_.Identity}},DeviceOS, lastsuccesssync
I just want to get an exact user name instead of a path in AD. How can I do it in expression={?}
Here is another script to do it, it gives me the user name, but all devices belongs to user are not in separated lines, they all in one line...
$EASMailboxes = Get-CASMailbox -Filter {HasActiveSyncDevicePartnership -eq $True -and DisplayName -notlike "CAS_{*"} | Get-Mailbox
$EASMailboxes | Select-Object DisplayName, PrimarySMTPAddress, #{Name="Mobile Devices";Expression={(Get-MobileDeviceStatistics -Mailbox $_.Identity).DeviceOS}} |
Out-GridView
I don't have the environment to test this but is this not what you are looking for ?
Get-Mailbox -ResultSize Unlimited | ForEach {
$user = $_.SamAccountName
Get-MobileDeviceStatistics -Mailbox:$_.Identity |
Select-Object #{label="User" ; expression={$user}},DeviceOS, lastsuccesssync
}
That should output the user for every device they own on its own line. You could then easily export this to Export-CSV or some such thing that way.
We save the $user so it is available later in the pipe. Could also have used Add-Member but the result would have been the same.
If you have the identity field, which looks like this
domain.com/Users/OU/UserName/ExchangeActiveSyncDevices/iPhone
Then to split on the / and get the third result, you simply request:
$_.Identity.Split("/")[3]
>UserName
PowerShell begins indexing with number zero, so to request the fourth entry in the list, we request index number 3.
Update
OP mentioned that the OU level might vary, meaning that he couldn't count on a fixed position to request the Index. In order to accomodte that scenario, try this method, which will look for the index of ExchangeActiveSyncDevices and then pick the index position before that.
$_.Identity.Split('/')[($_.Identity.Split('/').Indexof('ExchangeActiveSyncDevices')-1)]
Get-Mailbox -resultsize unlimited|foreach {Get-MobileDeviceStatistics -Mailbox:$_.identity} |Select-Object #{l="user";e={$_.Identity.parent.parent.name}}, lastsuccesssync
on e2k13