Passing previous Powershell command properties into a piped command - powershell

Can someone show how to pass a property from one Powershell command into the next piped command (in order to pull properties from both levels of the request)?
I need to get archive mailbox sizes for users in Exchange Online. An example of this is here:
Get-EXOMailbox | get-MailboxStatistics -archive | select displayname,totalitemsize
When you run this, obviously you are grabbing properties from the second command. I need to also grab the identity property tied to Get-EXOMAilbox, the first command (which shows the user's active mailbox and is useful for subsequent actions.
Thanks!

As Doug Maurer suggests, you might want to take advantage of the -PipelineVariable common parameter:
Get-EXOMailbox -PipelineVariable mailbox |Get-MailboxStatistics -Archive |Select #{Name='DisplayName';Expression={ $mailbox.DisplayName }},TotalItemSize

Related

Powershell: Pulling from a list (CSV) running a command and outputting to a different CSV

very new to heavier powershell and I've been hacking at this all day and can't figure it out.
I need to get a list of UPNs from office 365 accounts. I have the names in a CSV file. It has one column, with a long list of names. Heading is "name"
I want to run the get-user command against every name with the pipe format-list name, universalprincipalname and then output it to a new file.
I tried this:
get-content "m:\filename.csv" |
foreach {get-user '$_.user' -identity -resultsize unlimited} |
format-list name, userprincipalname |
out-file -FilePath m:\newfilename.csv
But it did not work (I also tried it with import-csv). It seemed to instead of pulling from my list, pull right from the office365 exchange server and when it finally finished had way more names in it than I have in my list.
My overall goal is to generate a list of upns of all the people who do not have mobile devices with their account so I can use a powershell command to disable active sync and OWA for mobile devices. Unfortunately, the command I used to generate my list of users produced the list in first name, last name format...and we have so many users I can't just concatenate the thing in excel, because there would be a ton of mistakes.
CSV is laid out like this:
Column1
name
first last
first last
first last
first last
Assuming the CSV's header is Name, the code should look like this:
Import-Csv "m:\filename.csv" | ForEach-Object {
Get-User -Identity $_.Name.Trim() -ResultSize Unlimited
} | Select-Object Name, UserPrincipalName |
Export-Csv "m:\newfilename.csv" -NoTypeInformation
Note that I'm using Select-Object instead of Format-Table. You should only use Format-Table to display your output to the PowerShell host, objects passed through the pipeline to this cmdlet will be recreated into a new object of the type FormatEntryData which you do not want if your intent is to export the data.

How to change ManagedBy owner from one user to another one for 150+ groups using power shell

I would like to change the Active Directory Group tab ManagedBy user to another one. With PowerShell script, I exported the groups with the old owner (>150) to a csv file. Now I need to change the owner of those groups using the csv file as input.
I don`t have much experience with scripting, I appreciate any help.
Thanks!
The task is very easy with PowerShell. You didn't show an example of the CSV data you exported so an example may not be exact. However, I assume you exported the default output of Get-ADGroup it might look something like this
(Import-Csv C:\temp\managedBy.csv).DistinguishedName| Set-ADGroup -ManagedBy <NewManager's DN>
Note: I like to use the DistinguishedName for these things but samAccountName should also work.
(Import-Csv C:\temp\managedBy.csv).samAccountName | Set-ADGroup -ManagedBy <NewsamAccountName>
Note: Again with the assumption that your Csv data is a direct export Get-ADGroups's output. You cannot pipe Import-Csv directly to Get/Set-ADGroup as the latter will have trouble determining which property to bind to the -Identity parameter.
However, I would point out you really don't need the intermediate Csv file. You can query AD directly for groups managed by the old manager and pipe that to a command to change the owner.
Get-ADGroup -Filter "ManagedBy -eq '<OldOwner'sDN>'" |
Set-ADGroup -ManagedBy "<NewOwner'sDN"
Note: Again you may be able to get away with using the samAccountName instead of the DN.
Note: You can add the WhatIf parameter to the Set-ADGroup` command to preview what will happen before actually running it.

Differences between | and $

Can anyone explain to me the differences I'm seeing in either using a | to pipe one command to another or using $ to 'pipe' it a different way (sorry not sure if the use $ is actually considering piping).
So… this works:
Get-Mailbox -ResultSize Unlimited |
where { $_.RecipientTypeDetails.tostring() -eq "SharedMailbox" } |
Get-MailboxPermission
Which is great, however because I want to place another where command after the Get-MailboxPermission which doesn't work above I then tried to use this:
$Mailbox = Get-Mailbox -ResultSize Unlimited |
where { $_.RecipientTypeDetails.tostring() -eq "SharedMailbox" }
Get-MailboxStatistics -Identity $Mailbox |
where { $_.IsInherited.tostring() -eq "False" }
It causes me to get this error:
Cannot process argument transformation on parameter 'Identity'. Cannot convert the "System.Collections.ArrayList" value of type "System.Collections.ArrayList" to type "Microsoft.Exchange.Configuration.Tasks.GeneralMailboxOrMailUserIdParameter".
Surely using | or $ is the same in the sense that it pipes through the results to the next command or am I completely wrong?
I don't have an exchange shell here to test but I guess I can still explain the basics and point you in the right direction.
The pipe | is used to redirect output from one command to another command. $ in Powershell is the character which defines that the character sequence right behind it is either a variable (e.g. $Mailbox as an example for a normal variable or $_ as an example for a variable that holds data that has been piped through from a previous command) or an expression. An example for an expression one is $(4+5).
Or in a more frequently used example:
PS C:\Users\Administrator> $file = (get-childitem)[0]
PS C:\Users\Administrator> write-output "The fullname of $file is $($file.fullname)"
The fullname of .ssh is C:\Users\Administrator\.ssh
In that example it is actually necessary to use an expression, because variable detection inside a string doesn't recognize dots as separator between variable and a variable member (fullname is a member of $file).
If it's not clear to you why there is a point and what members are, you should probably look into object oriented programming a bit because Powershell is object oriented through and through.
In your 2nd example you just save everything that's returned by your Get-Mailbox command in the $Mailbox variable. The $Mailbox variable is available as long as you don't delete it or leave its scope (in this case, the powershell session). You can actually use the variable as input for multiple commands without losing its data.
When using the pipe, the data returned by your first command is only accessible for the command behind the pipe and after that it's gone.
That's probably the difference you're interested in.
As for your actual problem: Powershell tells you that it's not expecting to be handed a variable of type System.Collections.ArrayList, which is what Get-Mailbox returns. The technet help is unclear as to what Get-Mailbox specificly returns, but I strongly guess it's an ArrayList of Mailbox-Objects. You can check it like this:
$Mailbox.GetType()
$Mailbox[0].GetType() # gets the type of the first object in $Mailbox
To fix your code, you need to loop over what's been returned by Get-Mailbox. Try this:
$Mailboxes = Get-Mailbox -ResultSize Unlimited | where { $_.RecipientTypeDetails.tostring() -eq "SharedMailbox" }
$Mailboxes | ForEach-Object { Get-MailboxStatistics -Identity $_ }
The ForEach-Object cmdlet loops over an array or a list and works on each item individually.
Your first example works so far because Powershell has been made smarter about piped data a few versions ago (See paragraph about 'Member Enumeration'). It's actually ForEach-ing over the passed in data.
Follow up links:
The $_ variable in powershell
Powershell is an object oriented language
Sorry to have to say this, but you're completely wrong. Pipelines and variables are two entirely different things.
The pipe (|) connects the output of one cmdlet to the input of another cmdlet. List output is processed one item at a time, i.e. the second cmdlet receives each list item separately.
If you collect a list of items in a variable ($mailbox) and call a cmdlet with that variable you're passing the list object instead of individual list items. That only works if the cmdlet parameter accepts array input.
The pipe operator | i used to flow the output of one command into the input of another command.
The dollar symbolc, $ is used to denote that the name following it is a variable, and has nothing to do with piping data between cmdlets. The where cmdlet create a $_ variable for use within its expression.

Get Memberships Of User

I have a very simple question but for some reason I can't seem to get my head around it.
I need a line of code that could be ran as a user from a client and lists all the "memeber of" groups from the AD (ONLY FOR THIS CURRENT USER). similar to
Get-ADGroupMember -identity "domain admins" -Recursive | foreach{ get-aduser $_} | select SamAccountName,objectclass,name
I would like the result to be listed.
I either need a way to import the AD module on a client computer or another way to contact the DC and get the users current "memeber of" groups.
/Niklas
I found the best way for my needs but CB.'s answer worked as well!
[ADSISEARCHER]"samaccountname=$($env:USERNAME)").Findone().Properties.memberof -replace '^CN=([^,]+).+$','$1'
I can then keep using this output in my code
you can use dos command line:
net user /domain %username%
The easiest way to do this would be with
Get-ADPrincipalGroupMembership -identity "Username"
Now this also means that you would have to have the active directory module loaded which you can find more information on its use on Technet Get-ADPrincipalGroupMember
If you simply want to produce a list, make a call to the command prompt as I find this works well, although it does truncate group names:
net user %username% /DOMAIN
If you want to programmatically get them and easily do something with that data, you'll want to rely on the Active Directory cmdlets.
To determine if you have these readily available in Powershell, you'll need to run the following command:
Get-Module –ListAvailable
If you don't see ActiveDirectory in the list you will need to first download and install the Windows Management Framework and import the module yourself:
Import-Module ActiveDirectory
Once that's done I believe this command should do the trick:
(Get-ADUser userName –Properties MemberOf | Select-Object MemberOf).MemberOf
Hopefully that gets you started. I'm fairly certain that there's more than one way to accomplish this with Powershell. Take a look at the Microsoft TechNet documentation to see if you can find something that better suits your needs.
Personally I have only ever needed to query AD group memberships ad-hoc for diagnostic purposes and have always relied on Get-ADUser or the command line call, depending on the target audience of the resulting data.

How can I filter mailboxes that have never been logged on in Exchange Management Shell?

I need to run a Get-Mailbox | Get-MailboxStatistics command across a large number of mailboxes but the majority have never been used as it is a new install. As a result, I have to sit through hundreds of lines of
WARNING: There is no data to return for the specified mailbox '<mailbox DN>' because it has not been logged on to.
It would seem that I need to use a server-side filter of some kind but I haven't been able to find anything appropriate.
What can I do here?
There is no server side filtering in Get-MailboxStatistics and I can't repro it. Can you try this:
Get-Mailbox | Get-MailboxStatistics -warningAction silentlyContinue
This is the standard PS behavior for warnings. You can find Shay's parameter in the help for common_parameters get-help about_common_parameters. Alternately, you can set $WarningPreference = silentlycontinue. There are no statistics to return as the mailboxes have not yet been initialized, hence the warning.