Xanderu
Xanderu

Reputation: 777

Powershell and Sharepoint - Update list

I've been reading a ton of these articles that say to use Get-SPWeb, but I've never been able to get those functions working due to authentication errors. I have build my own little functions to do what I need but I'm struggling to figure out what I'm doing wrong for my update function. Below are the functions I've built, and all of them work:

If (!$cred) {$cred = get-credential -UserName "$ENV:Username@$ENV:UserDomain.com" -Message "Enter your office 365 login"}

function Get-AuthenticationCookie($context)
{
    $sharePointUri = New-Object System.Uri($context.site.Url)
    $authCookie = $context.Credentials.GetAuthenticationCookie($sharePointUri)
    if ($? -eq $false) #https://ss64.com/ps/syntax-automatic-variables.html
    {
        return $null
    }
    $fedAuthString = $authCookie.TrimStart("SPOIDCRL=".ToCharArray())
    $cookieContainer = New-Object System.Net.CookieContainer
    $cookieContainer.Add($sharePointUri, (New-Object System.Net.Cookie("SPOIDCRL", $fedAuthString)))
    return $cookieContainer
}

function Get-SharepointContext
{
    Param(
        [Parameter(Mandatory = $true)]
        $siteUrl,
        [Parameter(Mandatory = $false)]
        $cred)

    If (!$cred) {$cred = get-credential -UserName "$ENV:Username@$env:USERDNSDOMAIN" -Message "Login"}

    [string]$username = $cred.UserName
    $securePassword = $cred.Password

    [Void][System.Reflection.Assembly]::LoadWithPartialName("Microsoft.SharePoint.Client")
    [Void][System.Reflection.Assembly]::LoadWithPartialName("Microsoft.SharePoint.Client.ClientContext")
    $ctx = New-Object Microsoft.SharePoint.Client.ClientContext($siteUrl)
    $ctx.RequestTimeOut = 1000 * 60 * 10;
    $ctx.AuthenticationMode = [Microsoft.SharePoint.Client.ClientAuthenticationMode]::Default
    $credentials = New-Object Microsoft.SharePoint.Client.SharePointOnlineCredentials($username, $securePassword)
    $ctx.Credentials = $credentials
    Return $ctx
}

function Add-SharepointListEntry
{
    #example
    #Add-SharepointListEntry -cred $cred -clientName $DestinationPages

    Param(
        [Parameter(Mandatory = $true)]
        $cred,
        [Parameter(Mandatory = $true)]
        $sitename,
        $siteUrl = "https://$env:Userdomain.sharepoint.com/$sitename",
        [Parameter(Mandatory = $true)]
        $ListName,
        $SharepointData
    )
    [Void][System.Reflection.Assembly]::LoadWithPartialName("Microsoft.SharePoint.Client")

    # Bind to site collection
    $Context = Get-SharepointContext -siteUrl $siteUrl -cred $cred

    # Get List
    $List = $Context.Web.Lists.GetByTitle($ListName)
    $Context.Load($List)
    $Context.ExecuteQuery()

    # Create Single List Item
    $ListItemCreationInformation = New-Object Microsoft.SharePoint.Client.ListItemCreationInformation
    $NewListItem = $List.AddItem($ListItemCreationInformation)

    #construct the entry to insert
    $NewListItem["Title"] = $SharepointData.Title #Client Name
    $NewListItem["Description"] = $SharepointData.Title

    #These objects should pass right through
    $NewListItem["Client"] = $SharepointData.Client
    $NewListItem["Author"] = $SharepointData.Author
    $NewListItem["Initials"] = $SharepointData.Author
    $NewListItem["Created"] = $SharepointData.Created

    $NewListItem.Update()
    $Context.ExecuteQuery()
}

Function Get-SharepointListData
{
    #example
    #Get-SharepointListData -cred $cred
    Param(
        [Parameter(Mandatory = $true)]
        $cred,
        [Parameter(Mandatory = $true)]
        $sitename,
        $siteUrl = "https://$env:Userdomain.sharepoint.com/$sitename",
        [Parameter(Mandatory = $true)]
        $ListName
    )

    [Void][System.Reflection.Assembly]::LoadWithPartialName("Microsoft.SharePoint.Client")
    # Bind to site collection
    $Context = Get-SharepointContext -siteUrl $siteUrl -cred $cred

    #Retrive the List
    $List = $Context.web.Lists.GetByTitle($ListName)

    #Get All List Items
    #reference https://gallery.technet.microsoft.com/office/How-to-do-a-CAML-Query-6f5260cf
    $Query = New-Object Microsoft.SharePoint.Client.CamlQuery
    $ListItems = $List.GetItems($Query)
    $context.Load($ListItems)
    $context.ExecuteQuery()

    # Turn item into a catch array
    $ListItemCollection = @()

    ForEach ($item in $ListItems)
    {
        $propertiesValues = New-Object PSObject
        $currentItem = $item
        $item.FieldValues.Keys | Where {$_ -ne "MetaInfo"} | ForEach {Add-Member -InputObject $propertiesValues -MemberType NoteProperty -Name $_ -Value $currentItem[$_]}
        $ListItemCollection += $propertiesValues
        Remove-Variable propertiesValues
    }
    Return $ListItemCollection
}

Now I'm building a new function and trying to use one list (which is querying a sharepoint folder) to update a sharepoint list. I query the directory with the get-sharepointlistdata, then loop through the results to add new entries if something is missing. This whole process works without issue. I'm trying to add a step in to update for any changes, but the function keeps failing on $list.Items.GetByID($index) throwing the error "You cannot call a method on a null-valued expression.":

    Function Set-SharepointListData
{
    Param(
        [Parameter(Mandatory = $true)]
        $cred,
        [Parameter(Mandatory = $true)]
        $sitename,
        $siteUrl = "https://$env:userdomain.sharepoint.com/$sitename",
        [Parameter(Mandatory = $true)]
        $ListName,
        [Parameter(Mandatory = $true)]
        [int]$Index,
        [Parameter(Mandatory = $true)]
        $Time
    )
    [Void][System.Reflection.Assembly]::LoadWithPartialName("Microsoft.SharePoint.Client")

    # Bind to site collection
    $Context = Get-SharepointContext -siteUrl $siteUrl -cred $cred

    # Get List
    $List = $Context.Web.Lists.GetByTitle($ListName)
    $Context.Load($List)
    $Context.ExecuteQuery()

    # Select Single List Item
    $ListItem = $List.Items.GetById($index)

    $ListItem["Created"] = $time
    $ListItem.Update();
    $Context.ExecuteQuery(); 
}

I'm certain I'm overlooking something obvious here... anyone have any ideas?

Upvotes: 0

Views: 646

Answers (1)

Peter Schneider
Peter Schneider

Reputation: 2929

The $Context.Web.Lists.GetByTitle($ListName) doesn't return the Items of the list. You have to load the Items... normally done via caml query. See here - Although the sample is in C# it should get you started.

Actually I rather suggest you to use PnPPowershell, there are plenty of cmdlets to work with Sharepoint.

Upvotes: 1

Related Questions