RipRapRob
RipRapRob

Reputation: 65

How do I make this PowerShell script 'loop' tru multiple arrays?

This PowerShell script works (not mine, I found it - data has been changed to dummy data here) - it Syncs Documents from a SharePoint Site to the users OneDrive:

#region Functions
function Sync-SharepointLocation {
    param (
        [guid]$siteId,
        [guid]$webId,
        [guid]$listId,
        [mailaddress]$userEmail,
        [string]$webUrl,
        [string]$webTitle,
        [string]$listTitle,
        [string]$syncPath
    )
    try {
        Add-Type -AssemblyName System.Web
        #Encode site, web, list, url & email
        [string]$siteId = [System.Web.HttpUtility]::UrlEncode($siteId)
        [string]$webId = [System.Web.HttpUtility]::UrlEncode($webId)
        [string]$listId = [System.Web.HttpUtility]::UrlEncode($listId)
        [string]$userEmail = [System.Web.HttpUtility]::UrlEncode($userEmail)
        [string]$webUrl = [System.Web.HttpUtility]::UrlEncode($webUrl)
        #build the URI
        $uri = New-Object System.UriBuilder
        $uri.Scheme = "odopen"
        $uri.Host = "sync"
        $uri.Query = "siteId=$siteId&webId=$webId&listId=$listId&userEmail=$userEmail&webUrl=$webUrl&listTitle=$listTitle&webTitle=$webTitle"
        #launch the process from URI
        Write-Host $uri.ToString()
        start-process -filepath $($uri.ToString())
    }
    catch {
        $errorMsg = $_.Exception.Message
    }
    if ($errorMsg) {
        Write-Warning "Sync failed."
        Write-Warning $errorMsg
    }
    else {
        Write-Host "Sync completed."
        while (!(Get-ChildItem -Path $syncPath -ErrorAction SilentlyContinue)) {
            Start-Sleep -Seconds 2
        }
        return $true
    }    
}
#endregion
#region Main Process
try {
    #region Sharepoint Sync
    [mailaddress]$userUpn = cmd /c "whoami/upn"
    $params = @{
        #replace with data captured from your sharepoint site.
        siteId    = "{11111111-1111-1111-11111111111111111}"
        webId     = "{22222222-2222-2222-22222222222222222}"
        listId    = "{33333333-3333-3333-33333333333333333}"
        userEmail = $userUpn
        webUrl    = "https://somecompany.sharepoint.com/sites/graphics"
        webTitle  = "graphics"
        listTitle = "Documents"
    }
    $params.syncPath  = "$(split-path $env:onedrive)\$($userUpn.Host)\$($params.webTitle) - $($Params.listTitle)"
    Write-Host "SharePoint params:"
    $params | Format-Table
    if (!(Test-Path $($params.syncPath))) {
        Write-Host "Sharepoint folder not found locally, will now sync.." -ForegroundColor Yellow
        $sp = Sync-SharepointLocation @params
        if (!($sp)) {
            Throw "Sharepoint sync failed."
        }
    }
    else {
        Write-Host "Location already syncronized: $($params.syncPath)" -ForegroundColor Yellow
    }
    #endregion
}
catch {
    $errorMsg = $_.Exception.Message
}
finally {
    if ($errorMsg) {
        Write-Warning $errorMsg
        Throw $errorMsg
    }
    else {
        Write-Host "Completed successfully.."
    }
}
#endregion

But I need do this for several SharePoint Sites, but I'd like to avoid having to run 10 different PowerPoint Scripts, if possible.

What I've tried:

I've made an array where I've defined the variables for all the sites, like this (with the correct data):

$params = @(

    [pscustomobject]@{
        siteId = "SiteID"; 
        webId = "webId"; 
        listId = "listId"; 
        userEmail = $userUpn; 
        webUrl = "webUrl"; 
        webTitle = "webTitle";
        listTitle = ""Documents"
        }

[Repeated for each Site]

)

I've then altered this part of the original code, to do a ForEach loop:

#region Main Process
try {
    #region Sharepoint Sync
    [mailaddress]$userUpn = cmd /c "whoami/upn"

    $params | ForEach-Object {

    $params.syncPath  = "$(split-path $env:onedrive)\$($userUpn.Host)\$($params.webTitle) - $($Params.listTitle)"
    Write-Host "SharePoint params:"
    $params | Format-Table
    if (!(Test-Path $($params.syncPath))) {
        Write-Host "Sharepoint folder not found locally, will now sync.." -ForegroundColor Yellow
        $sp = Sync-SharepointLocation @params
        if (!($sp)) {
            Throw "Sharepoint sync failed."
        }
    }
    else {
        Write-Host "Location already syncronized: $($params.syncPath)" -ForegroundColor Yellow
    }
    }
    #endregion
}

But it's not working as expected: Only the first Site in my Array is synced.

I'm a PowerShell beginner, so please help me: What am I doing wrong?

Thanks!

Upvotes: 1

Views: 206

Answers (1)

Mike
Mike

Reputation: 366

When looping through all the objects inside the $params array using a ForEach-Object, the object that you want to reference will be $_ .. not $params. So, where you are referencing $params.webTitle, etc., you should be referencing $_.webTitle, $_.listTitle, etc.

If you're new to Powershell, I would recommend you setting a variable like $paramObj for each instance using foreach ($parmObj in $params) {...} to make it clear what you are referencing, making the code look like:

# replaces the ForEach-Object
ForEach ($paramObj in $params) {
    Write-Host "SharePoint params:"
    $paramObj | Format-Table

    # i didn't see a syncPath in your $params custom object.. better if you set a local variable
    $syncPath  = "$(split-path $env:onedrive)\$($userUpn.Host)\$($paramObj.webTitle) - $($paramObj.listTitle)"

    if (!(Test-Path $($syncPath))) {
        Write-Host "Sharepoint folder not found locally, will now sync.." -ForegroundColor Yellow
        $sp = Sync-SharepointLocation @paramObj
        if (!($sp)) {
            Throw "Sharepoint sync failed."
        }
    }
    else {
        Write-Host "Location already syncronized: $syncPath" -ForegroundColor Yellow
    }
}

Upvotes: 2

Related Questions