#PowerShell, #PowerWiseScripting, #ProjectWise, PWPS_DAB

How To: Update ProjectWise Folder Security

In this post, I will go through the process of adding access control settings to a project folder. Then resetting and updating access control on each of the immediate children folders to the project. And finally updating access control for one sub-folder.

We will be using the following cmdlets to accomplish this task. All of the ProjectWise related cmdlets are available using the PWPS_DAB module. At the time of this post, I am using version 1.12.2.0. Take a look at the help for each of the cmdlets to become familiar with their functionality, available parameters, etc.

  • Get-PWCurrentDatasource
  • New-PWLogin
  • Undo-PWLogin
  • Get-PWFolders
  • Get-PWGroups
  • Get-PWUserLists
  • Get-PWFoldersImmediateChildren
  • Reset-PWFolderSecurity
  • Update-PWFolderSecurity

Parameters

First thing we need to do is create our parameter and value pairs. The help messages will explain the purpose for each parameter. I am also going to include a few requires statements to ensure the correct version of PowerShell and the PWPS_DAB module are used. As well as require that the Run As Administrator option is used to run the PowerShell Console or PowerShell ISE.

#Requires -Version 5.0
#Requires -Modules @{ModuleName="PWPS_DAB";ModuleVersion='1.12.2.0'}
#Requires -RunAsAdministrator
[CmdletBinding()]
param(
    [ValidateNotNullOrEmpty()]
    [Parameter(
        HelpMessage = 'Project folder.',
        Position = 0 )]
    [string] $ParentFolder = 'Projects\BSI900 - Adelaide Tower',
 
    [ValidateNotNullOrEmpty()]
    [ValidateSet('Group', 'UserList')]
    [Parameter(
        HelpMessage = 'Limiting MemberType to Group or UserList',
        Position = 1 )]
    [string] $MemberType = 'UserList',

    [ValidateNotNullOrEmpty()]
    [Parameter(
        HelpMessage = 'Name of group or userlist.',
        Position = 2 )]
    [string] $MemberName = 'Read_Only',

    [ValidateNotNullOrEmpty()]
    [Parameter(
        HelpMessage = 'Access control settings to use. See the help for Update-PWFolderSecurity possible MemberAccess values.',
        Position = 3 )]
    [string] $MemberAccess = ('r', 'w'),

    [ValidateNotNullOrEmpty()]
    [Parameter(
        HelpMessage = 'Project sub-folder.',
        Position = 4 )]
    [string] $subFolder = "$ParentFolder\01-WIP\CAD_Data',

    [ValidateNotNullOrEmpty()]
    [Parameter(
        HelpMessage = 'Name of group or userlist.',
        Position = 5 )]
    [string] $MemberName_CADD = 'CADD_Users',

    [ValidateNotNullOrEmpty()]
    [Parameter(
        HelpMessage = 'Access control settings to use. See the help for Update-PWFolderSecurity possible MemberAccess values.',
        Position = 6 )]
    [string] $MemberAccess_CADD = ('c', 'r', 'w', 'fr', 'fw')
) # end param

Begin

The next thing we will do is ensure we are logged into ProjectWise. If we are not logged into a ProjectWise datasource, the ProjectWise login dialog will be displayed.  I am going to add these steps into the BEGIN section of the script.

I want to take a second and point out a couple of conventions that I use in my scripts. First, you may notice that I put a comment at the end of many of the blocks of code. Doing this makes it easier for me to determine where a block of code starts and ends. Comes in handy when troubleshooting a script.  I also add text ([BEGIN], [PROCESS], [END]) in the output messages (Write-Verbose, Write-Warning, Write-Error) corresponding to the section of the script I am in. Again, this makes it obvious where something occurs within the script.

BEGIN {  
    $Continue = $true
    $StartTime = Get-Date 
    Write-Verbose -Message "[BEGIN] Start time: $StartTime" 

    <# Determine if we are currently logged into a ProjectWise datasource.  
        If not, display the ProjectWise Login Dialog. #> 
    if(Get-PWCurrentDatasource) { 
        Write-Verbose -Message "[BEGIN] Currently logged into ProjectWise datasource '$(Get-PWCurrentDatasource)'." 
    } else { 
        if(New-PWLogin -UseGui) { 
            Write-Verbose -Message "[BEGIN] Successfully logged into ProjectWise datasource '$(Get-PWCurrentDatasource)'." 
        } else { 
            Write-Error -Message '[BEGIN] Failed to log into ProjectWise datasource.' 
            $Continue = $false 
        } 
    } # end if(Get-PWCurrentDatasource... 
} # end BEGIN

PROCESS

Now that we are logged into a ProjectWise datasource, we can proceed to the PROCESS code block.

You can see that if the Continue variable equals false, a warning message will be displayed and we will proceed to the END code block to log out of ProjectWise and exit the script.

PROCESS { 
    if( -not ($Continue)) { 
        Write-Warning -Message "[PROCESS] Exiting script." 
    } else { ... } 
} # end PROCESS

Next we will use the value in the $ParentFolder variable to get the corresponding folder object. If the folder is not found, an error will be thrown and the script will end.

# We are going to wrap the core of the processing in a try / catch block.
try {
    # Determine if parent folder supplied is valid. If not, error out.
    $pwFolders = Get-PWFolders -FolderPath $ParentFolder -JustOne -ErrorAction Stop

Next we will need to verify  the provided member name exists. Again, if the member is not found, an error will be thrown and the script will end.

# Verify the member provided is valid.        
switch($MemberType) {
    'group' {
        $pwMemberResult = Get-PWGroups -GroupName $MemberName
        break
    }
    'userlist' { 
        $pwMemberResult = Get-PWUserLists -UserListName $MemberName
        break
    }
}
# If the member specified is not valid, throw an error message. Exit script.
if([string]::IsNullOrEmpty($pwMemberResult)) {
    throw("Specified member type does not exist.")
}

We will now populate a Splat with our parameter value pairs corresponding to the Update-PWFolderSecurity cmdlet. Then we will run the Update-PWFolderSecurity cmdlet to update the access control for the parent folder.

The following shows the access control settings for the parent folder.

ProjectFolder

# Add read-only userlist to the parent folder's Folder and Document Security.
# Using a Splat for readibility and reusability.
$SPlat_UpdateSecurity = @{              
    MemberType = $MemberType 
    MemberName = $MemberName
    MemberAccess = $MemberAccess
}
$SPlat_UpdateSecurity.InputFolder = $pwParentFolder
Update-PWFolderSecurity @SPlat_UpdateSecurity -FolderSecurity -ErrorAction Stop

The following shows the access control for the parent folder after updating the folder security. Notice that the Read_Only userlist has been added to folder security with read only permissions set. This will allow all users to see the folder, but not any documents contained in the folder.

ProjectFolder2

Next we will get an array of immediate child folder objects of the parent folder. We will be resetting and updating access control for each of these folders.

# Get immediate child folders to the parent project.
$pwImmediateChildFolders = Get-PWFoldersImmediateChildren -FolderID $pwParentFolder.ProjectID -ErrorAction Stop 

We now have our folder objects which we will loop through and reset and update access control for each.

The following shows the access control to one of the immediate child folders prior to updating. We want to remove all explicitly set access control for each of the immediate child folders. Both folder and document security.

ProjectFolder3

# Reset folder security for each of the child folders.
# The following is a counter for the progress bar. 
$Counter = 1
$ItemCount = $pwImmediateChildFolders.count
# Loop through each item in the collection. 
foreach($pwImmediateChildFolder in $pwImmediateChildFolders) {
    #region PROGRESS SECTION
    $Progress = @{
        Activity = "Resetting folder security for '$($pwImmediateChildFolder.Name)'."
        Status = "Processing $Counter of $ItemCount"
        PercentComplete = $([math]::Round($(($Counter / $ItemCount) * 100 ), 2))
    }
    Write-Progress @Progress -Id 1

    # Increment the counter.
    $Counter
    #endregion PROGRESS SECTION

    # Reset access control for the current child folder. 
    Reset-PWFolderSecurity -InputFolder $pwImmediateChildFolder -AllSecurity -ErrorAction Stop

The following shows that the access control has been reset for the 01-WIP folder. It is now inheriting permissions from the parent folder which is indicated by the small green downward pointing arrow icon.

ProjectFolder4

Now we will update the folder security for the 01-WIP folder. We will be adding the Read_Only user list to the documents permissions.

    # Update InputFolder value within the Splat.
    $SPlat_UpdateSecurity.InputFolder = $pwImmediateChildFolder
    # Add new member to document security for each folder. Keep the existing access control.
    Update-PWFolderSecurity @SPlat_UpdateSecurity -DocumentSecurity -IncludeInheritance -ErrorAction Continue
}

# Close the progress bar.
Write-Progress -Activity 'Completed processing.' -Id 1 -Completed

The following shows that access control for the 01-WIP folder has been updated to explicitly set the document permissions. This will allow all members of the Read_Only access list to view documents within the folder.

ProjectFolder5

Next, we want to explicitly set access control for the sub-folder 01-WIP\CAD_DATA. We will be adding the CADD_Users userlist to the document permissions only to allow for users to create and modify documents.

We will need to verify that the sub-folder exists, as well as the provided member name exists. Again, if either is invalid, an error will be thrown and the script will end.

    # Again, determine if folder supplied is valid. If not, error out.     
    $pwFolder = Get-PWFolders -FolderPath $subFolder -JustOne -ErrorAction Stop
    <# Again, verify the CADD member provided is valid.
         This could be put into a FUNCTIONs to eliminate duplicate code. #>
    switch($MemberType) {
        'group' {
            $pwMemberResult = Get-PWGroups -GroupName $MemberName
            break
        }
        'userlist' {
            $pwMemberResult = Get-PWUserLists -UserListName $MemberName_CADD
            break
        }
    }
    # If the member specified is not valid, throw an error message. Exit script.
    if([string]::IsNullOrEmpty($pwMemberResult)) {
        throw("Specified member type does not exist.")
    }

    # Update the values within the Splat.
    $SPlat_UpdateSecurity.InputFolder = $pwFolder
    $SPlat_UpdateSecurity.MemberName = $MemberName_CADD
    $SPlat_UpdateSecurity.MemberAccess = $MemberAccess_CADD
    # Add new member to document security for each folder. Keep the existing access control
    Update-PWFolderSecurity @SPlat_UpdateSecurity -DocumentSecurity -IncludeInheritance -ErrorAction Continue

} catch {
    $line = $_.InvocationInfo.ScriptLineNumber
    Write-Warning -Message "[PROCESS] $($Error[0].Exception.Message) Error occurred on line '$Line'."
} # end try / catch

The following shows that we have successfully added the CADD_Users userlist to the CAD_Data folder’s document security.

ProjectFolder7

We have completed all steps in the access control update process.


END

Lastly, we will proceed to the END block of code to log out of our ProjectWise session. You will also see that we have calculated the amount of time it had taken to complete the process.

END {
    $EndTime = Get-Date
    Write-Verbose -Message "[END] It took $([Math]::Round($EndTime.Subtract($StartTime).TotalMinutes, 2)) minutes to complete process."
    
    Write-Verbose -Message '[END] Logging out of ProjectWise.'
    Undo-PWLogin
} # end END

The following is a link to the full PowerShell script.

HowTo_UpdateProjectWiseFolderSecurity

Experiment with it and have fun.

Hopefully, you find this useful. Please let me know if you have any questions or comments.  If you like this post, please click the Like button at the bottom of the page.

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out /  Change )

Google photo

You are commenting using your Google account. Log Out /  Change )

Twitter picture

You are commenting using your Twitter account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

Connecting to %s

This site uses Akismet to reduce spam. Learn how your comment data is processed.