DSCResources/MSFT_SPProjectServerTimeSheetSettings/MSFT_SPProjectServerTimeSheetSettings.psm1

$script:resourceModulePath = Split-Path -Path (Split-Path -Path $PSScriptRoot -Parent) -Parent
$script:modulesFolderPath = Join-Path -Path $script:resourceModulePath -ChildPath 'Modules'
$script:resourceHelperModulePath = Join-Path -Path $script:modulesFolderPath -ChildPath 'SharePointDsc.Util'
Import-Module -Name (Join-Path -Path $script:resourceHelperModulePath -ChildPath 'SharePointDsc.Util.psm1')

function Get-TargetResource
{
    [CmdletBinding()]
    [OutputType([System.Collections.Hashtable])]
    param
    (
        [Parameter(Mandatory = $true)]
        [System.String]
        $Url,

        [Parameter()]
        [System.Boolean]
        $EnableOvertimeAndNonBillableTracking,

        [Parameter()]
        [ValidateSet("CurrentTaskAssignments", "CurrentProjects", "NoPrepopulation")]
        [System.String]
        $DefaultTimesheetCreationMode,

        [Parameter()]
        [ValidateSet("Days", "Weeks")]
        [System.String]
        $DefaultTrackingUnit,

        [Parameter()]
        [ValidateSet("Hours", "Days")]
        [System.String]
        $DefaultReportingUnit,

        [Parameter()]
        [System.Single]
        $HoursInStandardDay,

        [Parameter()]
        [System.Single]
        $HoursInStandardWeek,

        [Parameter()]
        [System.Single]
        $MaxHoursPerTimesheet,

        [Parameter()]
        [System.Single]
        $MinHoursPerTimesheet,

        [Parameter()]
        [System.Single]
        $MaxHoursPerDay,

        [Parameter()]
        [System.Boolean]
        $AllowFutureTimeReporting,

        [Parameter()]
        [System.Boolean]
        $AllowNewPersonalTasks,

        [Parameter()]
        [System.Boolean]
        $AllowTopLevelTimeReporting,

        [Parameter()]
        [System.Boolean]
        $RequireTaskStatusManagerApproval,

        [Parameter()]
        [System.Boolean]
        $RequireLineApprovalBeforeTimesheetApproval,

        [Parameter()]
        [System.Boolean]
        $EnableTimesheetAuditing,

        [Parameter()]
        [System.Boolean]
        $FixedApprovalRouting,

        [Parameter()]
        [System.Boolean]
        $SingleEntryMode,

        [Parameter()]
        [ValidateSet("PercentComplete", "ActualDoneAndRemaining", "HoursPerPeriod", "FreeForm")]
        [System.String]
        $DefaultTrackingMode,

        [Parameter()]
        [System.Boolean]
        $ForceTrackingModeForAllProjects,

        [Parameter()]
        [System.Management.Automation.PSCredential]
        $InstallAccount
    )

    Write-Verbose -Message "Getting Timesheet settings for $Url"

    if ((Get-SPDscInstalledProductVersion).FileMajorPart -lt 16)
    {
        throw [Exception] ("Support for Project Server in SharePointDsc is only valid for " + `
                "SharePoint 2016 and 2019.")
    }

    $result = Invoke-SPDscCommand -Credential $InstallAccount `
        -Arguments @($PSBoundParameters, $PSScriptRoot) `
        -ScriptBlock {
        $params = $args[0]
        $scriptRoot = $args[1]

        $modulePath = "..\..\Modules\SharePointDsc.ProjectServer\ProjectServerConnector.psm1"
        Import-Module -Name (Join-Path -Path $scriptRoot -ChildPath $modulePath -Resolve)

        $webAppUrl = (Get-SPSite -Identity $params.Url).WebApplication.Url
        $useKerberos = -not (Get-SPAuthenticationProvider -WebApplication $webAppUrl -Zone Default).DisableKerberos
        $adminService = New-SPDscProjectServerWebService -PwaUrl $params.Url `
            -EndpointName Admin `
            -UseKerberos:$useKerberos

        $script:currentSettings = $null
        Use-SPDscProjectServerWebService -Service $adminService -ScriptBlock {
            $script:currentSettings = $adminService.ReadTimeSheetSettings().TimeSheetSettings
        }

        if ($null -eq $script:currentSettings)
        {
            return @{
                Url                                        = $params.Url
                EnableOvertimeAndNonBillableTracking       = $false
                DefaultTimesheetCreationMode               = ""
                DefaultTrackingUnit                        = ""
                DefaultReportingUnit                       = ""
                HoursInStandardDay                         = 0
                HoursInStandardWeek                        = 0
                MaxHoursPerTimesheet                       = 0
                MinHoursPerTimesheet                       = 0
                MaxHoursPerDay                             = 0
                AllowFutureTimeReporting                   = $false
                AllowNewPersonalTasks                      = $false
                AllowTopLevelTimeReporting                 = $false
                RequireTaskStatusManagerApproval           = $false
                RequireLineApprovalBeforeTimesheetApproval = $false
                EnableTimesheetAuditing                    = $false
                FixedApprovalRouting                       = $false
                SingleEntryMode                            = $false
                DefaultTrackingMode                        = ""
                ForceTrackingModeForAllProjects            = $false
                InstallAccount                             = $params.InstallAccount
            }
        }
        else
        {
            $currentDefaultTimesheetCreationMode = "Unknown"
            switch ($script:currentSettings.WADMIN_TS_CREATE_MODE_ENUM)
            {
                1
                {
                    $currentDefaultTimesheetCreationMode = "CurrentTaskAssignments"
                }
                2
                {
                    $currentDefaultTimesheetCreationMode = "CurrentProjects"
                }
                0
                {
                    $currentDefaultTimesheetCreationMode = "NoPrepopulation"
                }
            }

            $currentDefaultTrackingUnit = "Unknown"
            switch ($script:currentSettings.WADMIN_TS_DEF_ENTRY_MODE_ENUM)
            {
                1
                {
                    $currentDefaultTrackingUnit = "Weeks"
                }
                0
                {
                    $currentDefaultTrackingUnit = "Days"
                }
            }

            $currentDefaultReportingUnit = "Unknown"
            switch ($script:currentSettings.WADMIN_TS_REPORT_UNIT_ENUM)
            {
                1
                {
                    $currentDefaultReportingUnit = "Days"
                }
                0
                {
                    $currentDefaultReportingUnit = "Hours"
                }
            }

            $currentDefaultTrackingMode = "Unknown"
            switch ($script:currentSettings.WADMIN_DEFAULT_TRACKING_METHOD)
            {
                3
                {
                    $currentDefaultTrackingMode = "ActualDoneAndRemaining"
                }
                2
                {
                    $currentDefaultTrackingMode = "PercentComplete"
                }
                1
                {
                    $currentDefaultTrackingMode = "HoursPerPeriod"
                }
                0
                {
                    $currentDefaultTrackingMode = "FreeForm"
                }
            }

            $currentEnableOvertimeAndNonBillableTracking = $false
            switch ($script:currentSettings.WADMIN_TS_DEF_DISPLAY_ENUM)
            {
                7
                {
                    $currentEnableOvertimeAndNonBillableTracking = $true
                }
                0
                {
                    $currentEnableOvertimeAndNonBillableTracking = $false
                }
            }

            return @{
                Url                                        = $params.Url
                EnableOvertimeAndNonBillableTracking       = $currentEnableOvertimeAndNonBillableTracking
                DefaultTimesheetCreationMode               = $currentDefaultTimesheetCreationMode
                DefaultTrackingUnit                        = $currentDefaultTrackingUnit
                DefaultReportingUnit                       = $currentDefaultReportingUnit
                HoursInStandardDay                         = ([System.Single]::Parse($script:currentSettings.WADMIN_TS_HOURS_PER_DAY) / 60000)
                HoursInStandardWeek                        = ([System.Single]::Parse($script:currentSettings.WADMIN_TS_HOURS_PER_WEEK) / 60000)
                MaxHoursPerTimesheet                       = ([System.Single]::Parse($script:currentSettings.WADMIN_TS_MAX_HR_PER_TS) / 60000)
                MinHoursPerTimesheet                       = ([System.Single]::Parse($script:currentSettings.WADMIN_TS_MIN_HR_PER_TS) / 60000)
                MaxHoursPerDay                             = ([System.Single]::Parse($script:currentSettings.WADMIN_TS_MAX_HR_PER_DAY) / 60000)
                AllowFutureTimeReporting                   = $script:currentSettings.WADMIN_TS_IS_FUTURE_REP_ALLOWED
                AllowNewPersonalTasks                      = $script:currentSettings.WADMIN_TS_IS_UNVERS_TASK_ALLOWED
                AllowTopLevelTimeReporting                 = $script:currentSettings.WADMIN_TS_ALLOW_PROJECT_LEVEL
                RequireTaskStatusManagerApproval           = $script:currentSettings.WADMIN_TS_PROJECT_MANAGER_COORDINATION
                RequireLineApprovalBeforeTimesheetApproval = $script:currentSettings.WADMIN_TS_PROJECT_MANAGER_APPROVAL
                EnableTimesheetAuditing                    = $script:currentSettings.WADMIN_TS_IS_AUDIT_ENABLED
                FixedApprovalRouting                       = $script:currentSettings.WADMIN_TS_FIXED_APPROVAL_ROUTING
                SingleEntryMode                            = $script:currentSettings.WADMIN_TS_TIED_MODE
                DefaultTrackingMode                        = $currentDefaultTrackingMode
                ForceTrackingModeForAllProjects            = $script:currentSettings.WADMIN_IS_TRACKING_METHOD_LOCKED
                InstallAccount                             = $params.InstallAccount
            }
        }
    }
    return $result
}


function Set-TargetResource
{
    [CmdletBinding()]
    param
    (
        [Parameter(Mandatory = $true)]
        [System.String]
        $Url,

        [Parameter()]
        [System.Boolean]
        $EnableOvertimeAndNonBillableTracking,

        [Parameter()]
        [ValidateSet("CurrentTaskAssignments", "CurrentProjects", "NoPrepopulation")]
        [System.String]
        $DefaultTimesheetCreationMode,

        [Parameter()]
        [ValidateSet("Days", "Weeks")]
        [System.String]
        $DefaultTrackingUnit,

        [Parameter()]
        [ValidateSet("Hours", "Days")]
        [System.String]
        $DefaultReportingUnit,

        [Parameter()]
        [System.Single]
        $HoursInStandardDay,

        [Parameter()]
        [System.Single]
        $HoursInStandardWeek,

        [Parameter()]
        [System.Single]
        $MaxHoursPerTimesheet,

        [Parameter()]
        [System.Single]
        $MinHoursPerTimesheet,

        [Parameter()]
        [System.Single]
        $MaxHoursPerDay,

        [Parameter()]
        [System.Boolean]
        $AllowFutureTimeReporting,

        [Parameter()]
        [System.Boolean]
        $AllowNewPersonalTasks,

        [Parameter()]
        [System.Boolean]
        $AllowTopLevelTimeReporting,

        [Parameter()]
        [System.Boolean]
        $RequireTaskStatusManagerApproval,

        [Parameter()]
        [System.Boolean]
        $RequireLineApprovalBeforeTimesheetApproval,

        [Parameter()]
        [System.Boolean]
        $EnableTimesheetAuditing,

        [Parameter()]
        [System.Boolean]
        $FixedApprovalRouting,

        [Parameter()]
        [System.Boolean]
        $SingleEntryMode,

        [Parameter()]
        [ValidateSet("PercentComplete", "ActualDoneAndRemaining", "HoursPerPeriod", "FreeForm")]
        [System.String]
        $DefaultTrackingMode,

        [Parameter()]
        [System.Boolean]
        $ForceTrackingModeForAllProjects,

        [Parameter()]
        [System.Management.Automation.PSCredential]
        $InstallAccount
    )

    Write-Verbose -Message "Setting Timesheet settings for $Url"

    if ((Get-SPDscInstalledProductVersion).FileMajorPart -lt 16)
    {
        throw [Exception] ("Support for Project Server in SharePointDsc is only valid for " + `
                "SharePoint 2016 and 2019.")
    }

    Invoke-SPDscCommand -Credential $InstallAccount `
        -Arguments $PSBoundParameters `
        -ScriptBlock {

        $params = $args[0]

        $webAppUrl = (Get-SPSite -Identity $params.Url).WebApplication.Url
        $useKerberos = -not (Get-SPAuthenticationProvider -WebApplication $webAppUrl -Zone Default).DisableKerberos
        $adminService = New-SPDscProjectServerWebService -PwaUrl $params.Url `
            -EndpointName Admin `
            -UseKerberos:$useKerberos

        Use-SPDscProjectServerWebService -Service $adminService -ScriptBlock {
            $settings = $adminService.ReadTimeSheetSettings()

            if ($params.ContainsKey("EnableOvertimeAndNonBillableTracking") -eq $true)
            {
                switch ($params.EnableOvertimeAndNonBillableTracking)
                {
                    $true
                    {
                        $settings.TimeSheetSettings.Rows[0]["WADMIN_TS_DEF_DISPLAY_ENUM"] = 7
                    }
                    $false
                    {
                        $settings.TimeSheetSettings.Rows[0]["WADMIN_TS_DEF_DISPLAY_ENUM"] = 0
                    }
                }
            }
            if ($params.ContainsKey("DefaultTimesheetCreationMode") -eq $true)
            {
                switch ($params.DefaultTimesheetCreationMode)
                {
                    "CurrentTaskAssignments"
                    {
                        $settings.TimeSheetSettings.Rows[0]["WADMIN_TS_CREATE_MODE_ENUM"] = 1
                    }
                    "CurrentProjects"
                    {
                        $settings.TimeSheetSettings.Rows[0]["WADMIN_TS_CREATE_MODE_ENUM"] = 2
                    }
                    "NoPrepopulation"
                    {
                        $settings.TimeSheetSettings.Rows[0]["WADMIN_TS_CREATE_MODE_ENUM"] = 0
                    }
                }
            }
            if ($params.ContainsKey("DefaultTrackingUnit") -eq $true)
            {
                switch ($params.DefaultTrackingUnit)
                {
                    "Weeks"
                    {
                        $settings.TimeSheetSettings.Rows[0]["WADMIN_TS_DEF_ENTRY_MODE_ENUM"] = 1
                    }
                    "Days"
                    {
                        $settings.TimeSheetSettings.Rows[0]["WADMIN_TS_DEF_ENTRY_MODE_ENUM"] = 0
                    }
                }
            }
            if ($params.ContainsKey("DefaultReportingUnit") -eq $true)
            {
                switch ($params.DefaultReportingUnit)
                {
                    "Days"
                    {
                        $settings.TimeSheetSettings.Rows[0]["WADMIN_TS_REPORT_UNIT_ENUM"] = 1
                    }
                    "Hours"
                    {
                        $settings.TimeSheetSettings.Rows[0]["WADMIN_TS_REPORT_UNIT_ENUM"] = 0
                    }
                }
            }
            if ($params.ContainsKey("HoursInStandardDay") -eq $true)
            {
                $settings.TimeSheetSettings.Rows[0]["WADMIN_TS_HOURS_PER_DAY"] = $params.HoursInStandardDay * 60000
            }
            if ($params.ContainsKey("HoursInStandardWeek") -eq $true)
            {
                $settings.TimeSheetSettings.Rows[0]["WADMIN_TS_HOURS_PER_WEEK"] = $params.HoursInStandardWeek * 60000
            }
            if ($params.ContainsKey("MaxHoursPerTimesheet") -eq $true)
            {
                $settings.TimeSheetSettings.Rows[0]["WADMIN_TS_MAX_HR_PER_TS"] = $params.MaxHoursPerTimesheet * 60000
            }
            if ($params.ContainsKey("MinHoursPerTimesheet") -eq $true)
            {
                $settings.TimeSheetSettings.Rows[0]["WADMIN_TS_MIN_HR_PER_TS"] = $params.MinHoursPerTimesheet * 60000
            }
            if ($params.ContainsKey("MaxHoursPerDay") -eq $true)
            {
                $settings.TimeSheetSettings.Rows[0]["WADMIN_TS_MAX_HR_PER_DAY"] = $params.MaxHoursPerDay * 60000
            }
            if ($params.ContainsKey("AllowFutureTimeReporting") -eq $true)
            {
                $settings.TimeSheetSettings.Rows[0]["WADMIN_TS_IS_FUTURE_REP_ALLOWED"] = $params.AllowFutureTimeReporting
            }
            if ($params.ContainsKey("AllowNewPersonalTasks") -eq $true)
            {
                $settings.TimeSheetSettings.Rows[0]["WADMIN_TS_IS_UNVERS_TASK_ALLOWED"] = $params.AllowNewPersonalTasks
            }
            if ($params.ContainsKey("AllowTopLevelTimeReporting") -eq $true)
            {
                $settings.TimeSheetSettings.Rows[0]["WADMIN_TS_ALLOW_PROJECT_LEVEL"] = $params.AllowTopLevelTimeReporting
            }
            if ($params.ContainsKey("RequireTaskStatusManagerApproval") -eq $true)
            {
                $settings.TimeSheetSettings.Rows[0]["WADMIN_TS_PROJECT_MANAGER_COORDINATION"] = $params.RequireTaskStatusManagerApproval
            }
            if ($params.ContainsKey("RequireLineApprovalBeforeTimesheetApproval") -eq $true)
            {
                $settings.TimeSheetSettings.Rows[0]["WADMIN_TS_PROJECT_MANAGER_APPROVAL"] = $params.RequireLineApprovalBeforeTimesheetApproval
            }
            if ($params.ContainsKey("EnableTimesheetAuditing") -eq $true)
            {
                $settings.TimeSheetSettings.Rows[0]["WADMIN_TS_IS_AUDIT_ENABLED"] = $params.EnableTimesheetAuditing
            }
            if ($params.ContainsKey("FixedApprovalRouting") -eq $true)
            {
                $settings.TimeSheetSettings.Rows[0]["WADMIN_TS_FIXED_APPROVAL_ROUTING"] = $params.FixedApprovalRouting
            }
            if ($params.ContainsKey("SingleEntryMode") -eq $true)
            {
                $settings.TimeSheetSettings.Rows[0]["WADMIN_TS_TIED_MODE"] = $params.SingleEntryMode
            }
            if ($params.ContainsKey("DefaultTrackingMode") -eq $true)
            {
                switch ($params.DefaultTrackingMode)
                {
                    "ActualDoneAndRemaining"
                    {
                        $settings.TimeSheetSettings.Rows[0]["WADMIN_DEFAULT_TRACKING_METHOD"] = 3
                    }
                    "PercentComplete"
                    {
                        $settings.TimeSheetSettings.Rows[0]["WADMIN_DEFAULT_TRACKING_METHOD"] = 2
                    }
                    "HoursPerPeriod"
                    {
                        $settings.TimeSheetSettings.Rows[0]["WADMIN_DEFAULT_TRACKING_METHOD"] = 1
                    }
                    "FreeForm"
                    {
                        $settings.TimeSheetSettings.Rows[0]["WADMIN_DEFAULT_TRACKING_METHOD"] = 0
                    }
                }
            }
            if ($params.ContainsKey("ForceTrackingModeForAllProjects") -eq $true)
            {
                $settings.TimeSheetSettings.Rows[0]["WADMIN_IS_TRACKING_METHOD_LOCKED"] = $params.ForceTrackingModeForAllProjects
            }

            $adminService.UpdateTimeSheetSettings($settings)
        }
    }
}


function Test-TargetResource
{
    [CmdletBinding()]
    [OutputType([System.Boolean])]
    param
    (
        [Parameter(Mandatory = $true)]
        [System.String]
        $Url,

        [Parameter()]
        [System.Boolean]
        $EnableOvertimeAndNonBillableTracking,

        [Parameter()]
        [ValidateSet("CurrentTaskAssignments", "CurrentProjects", "NoPrepopulation")]
        [System.String]
        $DefaultTimesheetCreationMode,

        [Parameter()]
        [ValidateSet("Days", "Weeks")]
        [System.String]
        $DefaultTrackingUnit,

        [Parameter()]
        [ValidateSet("Hours", "Days")]
        [System.String]
        $DefaultReportingUnit,

        [Parameter()]
        [System.Single]
        $HoursInStandardDay,

        [Parameter()]
        [System.Single]
        $HoursInStandardWeek,

        [Parameter()]
        [System.Single]
        $MaxHoursPerTimesheet,

        [Parameter()]
        [System.Single]
        $MinHoursPerTimesheet,

        [Parameter()]
        [System.Single]
        $MaxHoursPerDay,

        [Parameter()]
        [System.Boolean]
        $AllowFutureTimeReporting,

        [Parameter()]
        [System.Boolean]
        $AllowNewPersonalTasks,

        [Parameter()]
        [System.Boolean]
        $AllowTopLevelTimeReporting,

        [Parameter()]
        [System.Boolean]
        $RequireTaskStatusManagerApproval,

        [Parameter()]
        [System.Boolean]
        $RequireLineApprovalBeforeTimesheetApproval,

        [Parameter()]
        [System.Boolean]
        $EnableTimesheetAuditing,

        [Parameter()]
        [System.Boolean]
        $FixedApprovalRouting,

        [Parameter()]
        [System.Boolean]
        $SingleEntryMode,

        [Parameter()]
        [ValidateSet("PercentComplete", "ActualDoneAndRemaining", "HoursPerPeriod", "FreeForm")]
        [System.String]
        $DefaultTrackingMode,

        [Parameter()]
        [System.Boolean]
        $ForceTrackingModeForAllProjects,

        [Parameter()]
        [System.Management.Automation.PSCredential]
        $InstallAccount
    )

    Write-Verbose -Message "Testing Timesheet settings for $Url"

    $CurrentValues = Get-TargetResource @PSBoundParameters

    Write-Verbose -Message "Current Values: $(Convert-SPDscHashtableToString -Hashtable $CurrentValues)"
    Write-Verbose -Message "Target Values: $(Convert-SPDscHashtableToString -Hashtable $PSBoundParameters)"

    return Test-SPDscParameterState -CurrentValues $CurrentValues `
        -DesiredValues $PSBoundParameters
}

Export-ModuleMember -Function *-TargetResource