13

I created a custom object in PowerShell. I was able to solve the problem I wanted to solve. I wanted to have an object with two columns, one for the site collection, one for the email.

However, I am wondering if there is an easier solution. Do you have any suggestions?

Here is my code:

$cred = Get-Credential

Connect-PnPOnline "https://tenant.sharepoint.com" -Credentials $cred
$SiteCollections = Get-PnPTenantSite

$object = @()

foreach ($SiteCollection in $SiteCollections) {
    Connect-PnPOnline -Url $SiteCollection.Url -Credentials $cred
    $email = Get-PnPRequestAccessEmails
    Write-Host "Email for $($SiteCollection.Url): $($email)"

    $obj = New-Object System.Object
    $obj | Add-Member -type NoteProperty -name Url -value $SiteCollection.Url
    $obj | Add-Member -type NoteProperty -name Email -value $email
    $object += $obj
}

Write-Output $object
1

3 Answers 3

22

Objects can be constructed from a hashtable either with the New-Object cmdlet:

$obj = New-Object -Type PSObject -Property @{
    'Url'   = $SiteCollection.Url
    'Email' = $email
}

or (if you have PowerShell v3 or newer) the [PSCustomObject] type accelerator:

$obj = [PSCustomObject]@{
    'Url'   = $SiteCollection.Url
    'Email' = $email
}

Also, you can simply output the objects inside the loop and collect the entire loop output in a variable like this:

$object = @(foreach ($SiteCollection in $SiteCollections) {
    ...
    New-Object -Type PSObject -Property @{
        'Url'   = $SiteCollection.Url
        'Email' = $email
    }
})

The array subexpression operator (@()) around the foreach loop ensures that the result is an array, even if the loop output is less than 2 objects.

Using a calculated property would be another option:

$object = @(Get-PnPTenantSite | Select-Object Url, @{n='Email';e={
    Connect-PnPOnline -Url $_.Url -Credentials $cred | Out-Null
    Get-PnPRequestAccessEmails
}})
Sign up to request clarification or add additional context in comments.

3 Comments

Alternative to wrapping things in @(): I prefer to cast things to the [array] type, as it is easier for me to spot later on. Such as [array]$object = ForEach ($SiteCollection in $SiteCollections) {
I thought the whole array issue was in PowerShell v2 and earlier? Wouldn't using [pscustomobject] obviate the need to wrap the variable in an array?
@BaconBits Some issues were mitigated in PowerShell v3, yes, but you still won't magically get an array unless you make it happen. Consider for instance a situation where the loop doesn't return any results. In that case you'd end up with a null value. Trying to invoke a method on a null value would still give you an error, even in PowerShell v3 and newer. Also, I prefer to keep my answers backwards compatible if possible, although this answer doesn't set a good example. I should've used New-Object in the 3rd example.
3

Shortening the code a bit:

$cred = Get-Credential
Get-PnPTenantSite | ForEach-Object {
  Connect-PnPOnline -Url $_.Url -Credentials $cred
  [PSCustomObject] @{
    Url = $_.Url
    Email = Get-PnPRequestAccessEmails
  }
}

The [PSCustomObject] type accelerator only exists in PowerShell 3.0 and later.

Comments

0

Especially if your array is going to get very large, you might want to consider using an arraylist instead of a vanilla array. With a standard array, every time you add data to it, it recreates the whole array, as opposed to just tacking your data on the end. An arraylist simply appends and is much faster for building large arrays.

$outArray = New-Object System.Collections.ArrayList

foreach ($SiteCollection in $SiteCollections) {
    Connect-PnPOnline -Url $SiteCollection.Url -Credentials $cred
    $email = Get-PnPRequestAccessEmails
    Write-Host "Email for $($SiteCollection.Url): $($email)"

    $obj = New-Object System.Object
    $obj | Add-Member -type NoteProperty -name Url -value $SiteCollection.Url
    $obj | Add-Member -type NoteProperty -name Email -value $email
    [void]$outArray.Add($obj)
}

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.