diff --git a/CHANGELOG.md b/CHANGELOG.md index 981ea741..3d1081b3 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,6 +1,7 @@ # Changelog * [Changelog](#changelog) + * [2.27.0](#2270) * [2.26.4](#2264) * [2.26.3](#2263) * [2.26.2](#2262) @@ -86,6 +87,16 @@ *** +## 2.27.0 + +* [Issue #185](https://github.com/scrthq/PSGSuite/issues/185) + * Fixed: `Get-GSGroup -Where_IsAMember $member` no longer errors. +* [Issue #186](https://github.com/scrthq/PSGSuite/issues/186) + * Added: `Test-GSGroupMembership` to map to the [hasMember method](https://developers.google.com/admin-sdk/directory/v1/reference/members/hasMember). +* Miscellaneous + * Improved build process to auto-update NuGet dependencies. + * Added new private function `Resolve-Email` to convert a name-part or the case-sensitive `me` to the full email address accordingly. + ## 2.26.4 * [Issue #177](https://github.com/scrthq/PSGSuite/issues/177) - _Thanks, [@WJurecki](https://github.com/WJurecki)!_ diff --git a/PSGSuite/PSGSuite.psd1 b/PSGSuite/PSGSuite.psd1 index 8606f092..3d702e4f 100644 --- a/PSGSuite/PSGSuite.psd1 +++ b/PSGSuite/PSGSuite.psd1 @@ -12,7 +12,7 @@ RootModule = 'PSGSuite.psm1' # Version number of this module. - ModuleVersion = '2.26.4' + ModuleVersion = '2.27.0' # ID used to uniquely identify this module GUID = '9d751152-e83e-40bb-a6db-4c329092aaec' diff --git a/PSGSuite/Private/Resolve-Email.ps1 b/PSGSuite/Private/Resolve-Email.ps1 new file mode 100644 index 00000000..7e45e777 --- /dev/null +++ b/PSGSuite/Private/Resolve-Email.ps1 @@ -0,0 +1,20 @@ +function Resolve-Email { + [CmdletBinding()] + Param ( + [parameter(Mandatory,Position = 0,ValueFromPipeline,ValueFromPipelineByPropertyName)] + [Ref[]] + $Email + ) + Process { + foreach ($e in $Email) { + if ( -not ($e.value -as [decimal])) { + if ($e.value -ceq 'me') { + $e.value = $Script:PSGSuite.AdminEmail + } + elseif ($e.value -notlike "*@*.*") { + $e.value = "$($e.value)@$($Script:PSGSuite.Domain)" + } + } + } + } +} diff --git a/PSGSuite/Public/Groups/Add-GSGroupMember.ps1 b/PSGSuite/Public/Groups/Add-GSGroupMember.ps1 index f977168e..cc20b487 100644 --- a/PSGSuite/Public/Groups/Add-GSGroupMember.ps1 +++ b/PSGSuite/Public/Groups/Add-GSGroupMember.ps1 @@ -31,7 +31,7 @@ function Add-GSGroupMember { [String] $Identity, [parameter(Mandatory = $true,ValueFromPipelineByPropertyName = $true,Position = 1)] - [Alias("PrimaryEmail","UserKey","Mail","User","UserEmail")] + [Alias("PrimaryEmail","UserKey","Mail","User","UserEmail","Members")] [ValidateNotNullOrEmpty()] [String[]] $Member, @@ -53,8 +53,8 @@ function Add-GSGroupMember { $Identity = "$($Identity)@$($Script:PSGSuite.Domain)" } $groupObj = Get-GSGroup -Group $Identity -Verbose:$false - try { - foreach ($U in $Member) { + foreach ($U in $Member) { + try { if ($U -notlike "*@*.*") { $U = "$($U)@$($Script:PSGSuite.Domain)" } @@ -65,13 +65,13 @@ function Add-GSGroupMember { $request = $service.Members.Insert($body,$groupObj.Id) $request.Execute() | Add-Member -MemberType NoteProperty -Name 'Group' -Value $Identity -PassThru } - } - catch { - if ($ErrorActionPreference -eq 'Stop') { - $PSCmdlet.ThrowTerminatingError($_) - } - else { - Write-Error $_ + catch { + if ($ErrorActionPreference -eq 'Stop') { + $PSCmdlet.ThrowTerminatingError($_) + } + else { + Write-Error $_ + } } } } diff --git a/PSGSuite/Public/Groups/Get-GSGroup.ps1 b/PSGSuite/Public/Groups/Get-GSGroup.ps1 index 74c38f67..ef9d54c0 100644 --- a/PSGSuite/Public/Groups/Get-GSGroup.ps1 +++ b/PSGSuite/Public/Groups/Get-GSGroup.ps1 @@ -47,7 +47,7 @@ Gets the IT HelpDesk group by name using PowerShell syntax. PowerShell syntax is supported as a best effort, please refer to the Group Search documentation from Google for exact syntax. #> [OutputType('Google.Apis.Admin.Directory.directory_v1.Data.Group')] - [cmdletbinding(DefaultParameterSetName = "List")] + [cmdletbinding(DefaultParameterSetName = "ListFilter")] Param ( [parameter(Mandatory = $true,Position = 0,ValueFromPipeline = $true,ValueFromPipelineByPropertyName = $true,ParameterSetName = "Get")] @@ -55,20 +55,22 @@ [ValidateNotNullOrEmpty()] [String[]] $Group, - [parameter(Mandatory = $false,ParameterSetName = "List")] + [parameter(Mandatory = $false,ParameterSetName = "ListFilter")] [Alias('Query')] [string] $Filter, - [parameter(Mandatory = $false,ParameterSetName = "List")] + [parameter(Mandatory = $false,ParameterSetName = "ListWhereMember")] + [Alias('UserKey')] [String] $Where_IsAMember, - [parameter(Mandatory = $false,ParameterSetName = "List")] + [parameter(Mandatory = $false,ParameterSetName = "ListFilter")] [string] $Domain, [parameter(Mandatory = $false,ParameterSetName = "Get")] [String[]] $Fields, - [parameter(Mandatory = $false,ParameterSetName = "List")] + [parameter(Mandatory = $false,ParameterSetName = "ListFilter")] + [parameter(Mandatory = $false,ParameterSetName = "ListWhereMember")] [ValidateRange(1,200)] [Alias("MaxResults")] [Int] @@ -82,13 +84,11 @@ $service = New-GoogleService @serviceParams } Process { - switch ($PSCmdlet.ParameterSetName) { + switch -Regex ($PSCmdlet.ParameterSetName) { Get { foreach ($G in $Group) { try { - if ($G -notlike "*@*.*") { - $G = "$($G)@$($Script:PSGSuite.Domain)" - } + Resolve-Email ([ref]$G) Write-Verbose "Getting group '$G'" $request = $service.Groups.Get($G) if ($Fields) { @@ -106,21 +106,16 @@ } } } - List { + 'List.*' { $verbString = "Getting all G Suite Groups" try { $request = $service.Groups.List() if ($PSBoundParameters.Keys -contains 'Where_IsAMember') { - if ($Where_IsAMember -ceq "me") { - $Where_IsAMember = $Script:PSGSuite.AdminEmail - } - elseif ($Where_IsAMember -notlike "*@*.*") { - $Where_IsAMember = "$($Where_IsAMember)@$($Script:PSGSuite.Domain)" - } + Resolve-Email ([ref]$Where_IsAMember) $verbString += " where '$Where_IsAMember' is a member" $request.UserKey = $Where_IsAMember } - if ($PSBoundParameters.Keys -contains 'Filter') { + elseif ($PSBoundParameters.Keys -contains 'Filter') { if ($Filter -eq '*') { $Filter = "" } @@ -133,17 +128,19 @@ $request.Query = $Filter.Trim() } } - if ($PSBoundParameters.Keys -contains 'Domain') { - $verbString += " for domain '$Domain'" - $request.Domain = $Domain - } - elseif ( -not [String]::IsNullOrEmpty($Script:PSGSuite.CustomerID)) { - $verbString += " for customer '$($Script:PSGSuite.CustomerID)'" - $request.Customer = $Script:PSGSuite.CustomerID - } - else { - $verbString += " for customer 'my_customer'" - $request.Customer = "my_customer" + if ($PSBoundParameters.Keys -notcontains 'Where_IsAMember') { + if ($PSBoundParameters.Keys -contains 'Domain') { + $verbString += " for domain '$Domain'" + $request.Domain = $Domain + } + elseif ( -not [String]::IsNullOrEmpty($Script:PSGSuite.CustomerID)) { + $verbString += " for customer '$($Script:PSGSuite.CustomerID)'" + $request.Customer = $Script:PSGSuite.CustomerID + } + else { + $verbString += " for customer 'my_customer'" + $request.Customer = "my_customer" + } } if ($PageSize) { $request.MaxResults = $PageSize diff --git a/PSGSuite/Public/Groups/Get-GSGroupMember.ps1 b/PSGSuite/Public/Groups/Get-GSGroupMember.ps1 index 61df2d2e..0c3e232f 100644 --- a/PSGSuite/Public/Groups/Get-GSGroupMember.ps1 +++ b/PSGSuite/Public/Groups/Get-GSGroupMember.ps1 @@ -31,7 +31,7 @@ function Get-GSGroupMember { [String[]] $Identity, [parameter(Mandatory = $false,Position = 1,ParameterSetName = "Get")] - [Alias("PrimaryEmail","UserKey","Mail","User","UserEmail")] + [Alias("PrimaryEmail","UserKey","Mail","User","UserEmail","Members")] [ValidateNotNullOrEmpty()] [String[]] $Member, diff --git a/PSGSuite/Public/Groups/Remove-GSGroupMember.ps1 b/PSGSuite/Public/Groups/Remove-GSGroupMember.ps1 index 5336d6bb..39491daa 100644 --- a/PSGSuite/Public/Groups/Remove-GSGroupMember.ps1 +++ b/PSGSuite/Public/Groups/Remove-GSGroupMember.ps1 @@ -2,16 +2,16 @@ function Remove-GSGroupMember { <# .SYNOPSIS Removes members from a group - + .DESCRIPTION Removes members from a group - + .PARAMETER Identity The email or unique Id of the group to remove members from - + .PARAMETER Member The member or array of members to remove from the target group - + .EXAMPLE Remove-GSGroupMember -Identity admins -Member joe.smith,mark.taylor -Confirm:$false @@ -25,7 +25,7 @@ function Remove-GSGroupMember { [String] $Identity, [parameter(Mandatory = $true,ValueFromPipelineByPropertyName = $true,Position = 1)] - [Alias("PrimaryEmail","UserKey","Mail","User","UserEmail")] + [Alias("PrimaryEmail","UserKey","Mail","User","UserEmail","Members")] [ValidateNotNullOrEmpty()] [String[]] $Member @@ -63,4 +63,4 @@ function Remove-GSGroupMember { } } } -} \ No newline at end of file +} diff --git a/PSGSuite/Public/Groups/Test-GSGroupMembership.ps1 b/PSGSuite/Public/Groups/Test-GSGroupMembership.ps1 new file mode 100644 index 00000000..8e3fc951 --- /dev/null +++ b/PSGSuite/Public/Groups/Test-GSGroupMembership.ps1 @@ -0,0 +1,59 @@ +function Test-GSGroupMembership { + <# + .SYNOPSIS + Checks if a Group has a specific member + + .DESCRIPTION + Checks if a Group has a specific member + + .PARAMETER Identity + The email of the group + + If only the email name-part is passed, the full email will be contstructed using the Domain from the active config + + .PARAMETER Member + The user to confirm as a member of the Group + + .EXAMPLE + Test-GSGroupMembership -Identity admins@domain.com -Member john@domain.com + + Gets the group settings for admins@domain.com + #> + [OutputType('Google.Apis.Admin.Directory.directory_v1.Data.MembersHasMember')] + [cmdletbinding()] + Param + ( + [parameter(Mandatory = $true,Position = 0,ValueFromPipeline = $true,ValueFromPipelineByPropertyName = $true)] + [Alias('GroupEmail','Group','Email')] + [String] + $Identity, + [parameter(Mandatory = $true,ValueFromPipelineByPropertyName = $true,Position = 1)] + [Alias("PrimaryEmail","UserKey","Mail","User","UserEmail","Members")] + [ValidateNotNullOrEmpty()] + [String] + $Member + ) + Begin { + $serviceParams = @{ + Scope = 'https://www.googleapis.com/auth/admin.directory.group' + ServiceType = 'Google.Apis.Admin.Directory.directory_v1.DirectoryService' + } + $service = New-GoogleService @serviceParams + } + Process { + try { + Resolve-Email ([ref]$Identity),([ref]$Member) + Write-Verbose "Checking if group '$Identity' has member '$Member'" + $request = $service.Members.HasMember($Identity,$Member) + $request.Execute() | Add-Member -MemberType NoteProperty -Name 'Group' -Value $Identity -Force -PassThru | Add-Member -MemberType NoteProperty -Name 'Member' -Value $Member -Force -PassThru + } + catch { + if ($ErrorActionPreference -eq 'Stop') { + $PSCmdlet.ThrowTerminatingError($_) + } + else { + Write-Error $_ + } + } + } +} diff --git a/PSGSuite/Public/Groups/Update-GSGroupMember.ps1 b/PSGSuite/Public/Groups/Update-GSGroupMember.ps1 index f591adb5..1a112cc1 100644 --- a/PSGSuite/Public/Groups/Update-GSGroupMember.ps1 +++ b/PSGSuite/Public/Groups/Update-GSGroupMember.ps1 @@ -44,7 +44,7 @@ function Update-GSGroupMember { [String] $GroupEmail, [parameter(Mandatory = $true,Position = 1,ValueFromPipelineByPropertyName = $true)] - [Alias("PrimaryEmail","UserKey","Mail","User","UserEmail","Email")] + [Alias("PrimaryEmail","UserKey","Mail","User","UserEmail","Email","Members")] [ValidateNotNullOrEmpty()] [String[]] $Member, diff --git a/PSGSuite/Public/Users/Get-GSUser.ps1 b/PSGSuite/Public/Users/Get-GSUser.ps1 index 7047c7ed..c65ea884 100644 --- a/PSGSuite/Public/Users/Get-GSUser.ps1 +++ b/PSGSuite/Public/Users/Get-GSUser.ps1 @@ -160,14 +160,7 @@ function Get-GSUser { if ($MyInvocation.InvocationName -ne 'Get-GSUserList' -and $PSCmdlet.ParameterSetName -eq 'Get') { foreach ($U in $User) { try { - if ( -not ($U -as [decimal])) { - if ($U -ceq 'me') { - $U = $Script:PSGSuite.AdminEmail - } - elseif ($U -notlike "*@*.*") { - $U = "$($U)@$($Script:PSGSuite.Domain)" - } - } + Resolve-Email ([ref]$U) Write-Verbose "Getting User '$U'" $request = $service.Users.Get($U) $request.Projection = $Projection diff --git a/PSGSuite/lib/net45/BouncyCastle.Crypto.dll b/PSGSuite/lib/net45/BouncyCastle.Crypto.dll deleted file mode 100644 index 615297ca..00000000 Binary files a/PSGSuite/lib/net45/BouncyCastle.Crypto.dll and /dev/null differ diff --git a/PSGSuite/lib/net45/Google.Apis.Admin.DataTransfer.datatransfer_v1.dll b/PSGSuite/lib/net45/Google.Apis.Admin.DataTransfer.datatransfer_v1.dll deleted file mode 100644 index 49ad11f2..00000000 Binary files a/PSGSuite/lib/net45/Google.Apis.Admin.DataTransfer.datatransfer_v1.dll and /dev/null differ diff --git a/PSGSuite/lib/net45/Google.Apis.Admin.Directory.directory_v1.dll b/PSGSuite/lib/net45/Google.Apis.Admin.Directory.directory_v1.dll deleted file mode 100644 index 4100967e..00000000 Binary files a/PSGSuite/lib/net45/Google.Apis.Admin.Directory.directory_v1.dll and /dev/null differ diff --git a/PSGSuite/lib/net45/Google.Apis.Admin.Reports.reports_v1.dll b/PSGSuite/lib/net45/Google.Apis.Admin.Reports.reports_v1.dll deleted file mode 100644 index 4c142543..00000000 Binary files a/PSGSuite/lib/net45/Google.Apis.Admin.Reports.reports_v1.dll and /dev/null differ diff --git a/PSGSuite/lib/net45/Google.Apis.Auth.PlatformServices.dll b/PSGSuite/lib/net45/Google.Apis.Auth.PlatformServices.dll deleted file mode 100644 index f65a3bfc..00000000 Binary files a/PSGSuite/lib/net45/Google.Apis.Auth.PlatformServices.dll and /dev/null differ diff --git a/PSGSuite/lib/net45/Google.Apis.Auth.dll b/PSGSuite/lib/net45/Google.Apis.Auth.dll deleted file mode 100644 index dbae4651..00000000 Binary files a/PSGSuite/lib/net45/Google.Apis.Auth.dll and /dev/null differ diff --git a/PSGSuite/lib/net45/Google.Apis.Calendar.v3.dll b/PSGSuite/lib/net45/Google.Apis.Calendar.v3.dll deleted file mode 100644 index 27954d87..00000000 Binary files a/PSGSuite/lib/net45/Google.Apis.Calendar.v3.dll and /dev/null differ diff --git a/PSGSuite/lib/net45/Google.Apis.Classroom.v1.dll b/PSGSuite/lib/net45/Google.Apis.Classroom.v1.dll deleted file mode 100644 index 2dbb57d9..00000000 Binary files a/PSGSuite/lib/net45/Google.Apis.Classroom.v1.dll and /dev/null differ diff --git a/PSGSuite/lib/net45/Google.Apis.Core.dll b/PSGSuite/lib/net45/Google.Apis.Core.dll deleted file mode 100644 index dc421570..00000000 Binary files a/PSGSuite/lib/net45/Google.Apis.Core.dll and /dev/null differ diff --git a/PSGSuite/lib/net45/Google.Apis.Docs.v1.dll b/PSGSuite/lib/net45/Google.Apis.Docs.v1.dll deleted file mode 100644 index 98ccd29b..00000000 Binary files a/PSGSuite/lib/net45/Google.Apis.Docs.v1.dll and /dev/null differ diff --git a/PSGSuite/lib/net45/Google.Apis.Drive.v3.dll b/PSGSuite/lib/net45/Google.Apis.Drive.v3.dll deleted file mode 100644 index 84bb00a3..00000000 Binary files a/PSGSuite/lib/net45/Google.Apis.Drive.v3.dll and /dev/null differ diff --git a/PSGSuite/lib/net45/Google.Apis.DriveActivity.v2.dll b/PSGSuite/lib/net45/Google.Apis.DriveActivity.v2.dll deleted file mode 100644 index b1a90b43..00000000 Binary files a/PSGSuite/lib/net45/Google.Apis.DriveActivity.v2.dll and /dev/null differ diff --git a/PSGSuite/lib/net45/Google.Apis.Gmail.v1.dll b/PSGSuite/lib/net45/Google.Apis.Gmail.v1.dll deleted file mode 100644 index 9a378d8a..00000000 Binary files a/PSGSuite/lib/net45/Google.Apis.Gmail.v1.dll and /dev/null differ diff --git a/PSGSuite/lib/net45/Google.Apis.Groupssettings.v1.dll b/PSGSuite/lib/net45/Google.Apis.Groupssettings.v1.dll deleted file mode 100644 index 556877e6..00000000 Binary files a/PSGSuite/lib/net45/Google.Apis.Groupssettings.v1.dll and /dev/null differ diff --git a/PSGSuite/lib/net45/Google.Apis.HangoutsChat.v1.dll b/PSGSuite/lib/net45/Google.Apis.HangoutsChat.v1.dll deleted file mode 100644 index 48726932..00000000 Binary files a/PSGSuite/lib/net45/Google.Apis.HangoutsChat.v1.dll and /dev/null differ diff --git a/PSGSuite/lib/net45/Google.Apis.Licensing.v1.dll b/PSGSuite/lib/net45/Google.Apis.Licensing.v1.dll deleted file mode 100644 index ad664a26..00000000 Binary files a/PSGSuite/lib/net45/Google.Apis.Licensing.v1.dll and /dev/null differ diff --git a/PSGSuite/lib/net45/Google.Apis.Oauth2.v2.dll b/PSGSuite/lib/net45/Google.Apis.Oauth2.v2.dll deleted file mode 100644 index a5384166..00000000 Binary files a/PSGSuite/lib/net45/Google.Apis.Oauth2.v2.dll and /dev/null differ diff --git a/PSGSuite/lib/net45/Google.Apis.PeopleService.v1.dll b/PSGSuite/lib/net45/Google.Apis.PeopleService.v1.dll deleted file mode 100644 index 0a34efc3..00000000 Binary files a/PSGSuite/lib/net45/Google.Apis.PeopleService.v1.dll and /dev/null differ diff --git a/PSGSuite/lib/net45/Google.Apis.PlatformServices.dll b/PSGSuite/lib/net45/Google.Apis.PlatformServices.dll deleted file mode 100644 index ebb0a51e..00000000 Binary files a/PSGSuite/lib/net45/Google.Apis.PlatformServices.dll and /dev/null differ diff --git a/PSGSuite/lib/net45/Google.Apis.Script.v1.dll b/PSGSuite/lib/net45/Google.Apis.Script.v1.dll deleted file mode 100644 index 906c7282..00000000 Binary files a/PSGSuite/lib/net45/Google.Apis.Script.v1.dll and /dev/null differ diff --git a/PSGSuite/lib/net45/Google.Apis.Sheets.v4.dll b/PSGSuite/lib/net45/Google.Apis.Sheets.v4.dll deleted file mode 100644 index ddf9f2de..00000000 Binary files a/PSGSuite/lib/net45/Google.Apis.Sheets.v4.dll and /dev/null differ diff --git a/PSGSuite/lib/net45/Google.Apis.Slides.v1.dll b/PSGSuite/lib/net45/Google.Apis.Slides.v1.dll deleted file mode 100644 index 3906c8ff..00000000 Binary files a/PSGSuite/lib/net45/Google.Apis.Slides.v1.dll and /dev/null differ diff --git a/PSGSuite/lib/net45/Google.Apis.Tasks.v1.dll b/PSGSuite/lib/net45/Google.Apis.Tasks.v1.dll deleted file mode 100644 index c1aef6fc..00000000 Binary files a/PSGSuite/lib/net45/Google.Apis.Tasks.v1.dll and /dev/null differ diff --git a/PSGSuite/lib/net45/Google.Apis.Urlshortener.v1.dll b/PSGSuite/lib/net45/Google.Apis.Urlshortener.v1.dll deleted file mode 100644 index 0f3be77e..00000000 Binary files a/PSGSuite/lib/net45/Google.Apis.Urlshortener.v1.dll and /dev/null differ diff --git a/PSGSuite/lib/net45/Google.Apis.dll b/PSGSuite/lib/net45/Google.Apis.dll deleted file mode 100644 index eab25372..00000000 Binary files a/PSGSuite/lib/net45/Google.Apis.dll and /dev/null differ diff --git a/PSGSuite/lib/net45/MimeKit.dll b/PSGSuite/lib/net45/MimeKit.dll deleted file mode 100644 index c29dcb7f..00000000 Binary files a/PSGSuite/lib/net45/MimeKit.dll and /dev/null differ diff --git a/PSGSuite/lib/net45/Newtonsoft.Json.dll b/PSGSuite/lib/net45/Newtonsoft.Json.dll deleted file mode 100644 index 77a5d89e..00000000 Binary files a/PSGSuite/lib/net45/Newtonsoft.Json.dll and /dev/null differ diff --git a/PSGSuite/lib/netstandard1.3/BouncyCastle.Crypto.dll b/PSGSuite/lib/netstandard1.3/BouncyCastle.Crypto.dll deleted file mode 100644 index 7aee68dd..00000000 Binary files a/PSGSuite/lib/netstandard1.3/BouncyCastle.Crypto.dll and /dev/null differ diff --git a/PSGSuite/lib/netstandard1.3/Google.Apis.Admin.DataTransfer.datatransfer_v1.dll b/PSGSuite/lib/netstandard1.3/Google.Apis.Admin.DataTransfer.datatransfer_v1.dll deleted file mode 100644 index 3f4c4653..00000000 Binary files a/PSGSuite/lib/netstandard1.3/Google.Apis.Admin.DataTransfer.datatransfer_v1.dll and /dev/null differ diff --git a/PSGSuite/lib/netstandard1.3/Google.Apis.Admin.Directory.directory_v1.dll b/PSGSuite/lib/netstandard1.3/Google.Apis.Admin.Directory.directory_v1.dll deleted file mode 100644 index 34c10308..00000000 Binary files a/PSGSuite/lib/netstandard1.3/Google.Apis.Admin.Directory.directory_v1.dll and /dev/null differ diff --git a/PSGSuite/lib/netstandard1.3/Google.Apis.Admin.Reports.reports_v1.dll b/PSGSuite/lib/netstandard1.3/Google.Apis.Admin.Reports.reports_v1.dll deleted file mode 100644 index 5c0169a8..00000000 Binary files a/PSGSuite/lib/netstandard1.3/Google.Apis.Admin.Reports.reports_v1.dll and /dev/null differ diff --git a/PSGSuite/lib/netstandard1.3/Google.Apis.Auth.PlatformServices.dll b/PSGSuite/lib/netstandard1.3/Google.Apis.Auth.PlatformServices.dll deleted file mode 100644 index d3e643da..00000000 Binary files a/PSGSuite/lib/netstandard1.3/Google.Apis.Auth.PlatformServices.dll and /dev/null differ diff --git a/PSGSuite/lib/netstandard1.3/Google.Apis.Auth.dll b/PSGSuite/lib/netstandard1.3/Google.Apis.Auth.dll deleted file mode 100644 index 068718b6..00000000 Binary files a/PSGSuite/lib/netstandard1.3/Google.Apis.Auth.dll and /dev/null differ diff --git a/PSGSuite/lib/netstandard1.3/Google.Apis.Calendar.v3.dll b/PSGSuite/lib/netstandard1.3/Google.Apis.Calendar.v3.dll deleted file mode 100644 index a35d3ce3..00000000 Binary files a/PSGSuite/lib/netstandard1.3/Google.Apis.Calendar.v3.dll and /dev/null differ diff --git a/PSGSuite/lib/netstandard1.3/Google.Apis.Classroom.v1.dll b/PSGSuite/lib/netstandard1.3/Google.Apis.Classroom.v1.dll deleted file mode 100644 index e57ee221..00000000 Binary files a/PSGSuite/lib/netstandard1.3/Google.Apis.Classroom.v1.dll and /dev/null differ diff --git a/PSGSuite/lib/netstandard1.3/Google.Apis.Core.dll b/PSGSuite/lib/netstandard1.3/Google.Apis.Core.dll deleted file mode 100644 index 761e3dda..00000000 Binary files a/PSGSuite/lib/netstandard1.3/Google.Apis.Core.dll and /dev/null differ diff --git a/PSGSuite/lib/netstandard1.3/Google.Apis.Docs.v1.dll b/PSGSuite/lib/netstandard1.3/Google.Apis.Docs.v1.dll deleted file mode 100644 index 866876c9..00000000 Binary files a/PSGSuite/lib/netstandard1.3/Google.Apis.Docs.v1.dll and /dev/null differ diff --git a/PSGSuite/lib/netstandard1.3/Google.Apis.Drive.v3.dll b/PSGSuite/lib/netstandard1.3/Google.Apis.Drive.v3.dll deleted file mode 100644 index 96890800..00000000 Binary files a/PSGSuite/lib/netstandard1.3/Google.Apis.Drive.v3.dll and /dev/null differ diff --git a/PSGSuite/lib/netstandard1.3/Google.Apis.DriveActivity.v2.dll b/PSGSuite/lib/netstandard1.3/Google.Apis.DriveActivity.v2.dll deleted file mode 100644 index 601abb96..00000000 Binary files a/PSGSuite/lib/netstandard1.3/Google.Apis.DriveActivity.v2.dll and /dev/null differ diff --git a/PSGSuite/lib/netstandard1.3/Google.Apis.Gmail.v1.dll b/PSGSuite/lib/netstandard1.3/Google.Apis.Gmail.v1.dll deleted file mode 100644 index a094c57a..00000000 Binary files a/PSGSuite/lib/netstandard1.3/Google.Apis.Gmail.v1.dll and /dev/null differ diff --git a/PSGSuite/lib/netstandard1.3/Google.Apis.Groupssettings.v1.dll b/PSGSuite/lib/netstandard1.3/Google.Apis.Groupssettings.v1.dll deleted file mode 100644 index 8c5a0538..00000000 Binary files a/PSGSuite/lib/netstandard1.3/Google.Apis.Groupssettings.v1.dll and /dev/null differ diff --git a/PSGSuite/lib/netstandard1.3/Google.Apis.HangoutsChat.v1.dll b/PSGSuite/lib/netstandard1.3/Google.Apis.HangoutsChat.v1.dll deleted file mode 100644 index be088979..00000000 Binary files a/PSGSuite/lib/netstandard1.3/Google.Apis.HangoutsChat.v1.dll and /dev/null differ diff --git a/PSGSuite/lib/netstandard1.3/Google.Apis.Licensing.v1.dll b/PSGSuite/lib/netstandard1.3/Google.Apis.Licensing.v1.dll deleted file mode 100644 index a430a7d9..00000000 Binary files a/PSGSuite/lib/netstandard1.3/Google.Apis.Licensing.v1.dll and /dev/null differ diff --git a/PSGSuite/lib/netstandard1.3/Google.Apis.Oauth2.v2.dll b/PSGSuite/lib/netstandard1.3/Google.Apis.Oauth2.v2.dll deleted file mode 100644 index c4ca9c6f..00000000 Binary files a/PSGSuite/lib/netstandard1.3/Google.Apis.Oauth2.v2.dll and /dev/null differ diff --git a/PSGSuite/lib/netstandard1.3/Google.Apis.PeopleService.v1.dll b/PSGSuite/lib/netstandard1.3/Google.Apis.PeopleService.v1.dll deleted file mode 100644 index 7b94cc55..00000000 Binary files a/PSGSuite/lib/netstandard1.3/Google.Apis.PeopleService.v1.dll and /dev/null differ diff --git a/PSGSuite/lib/netstandard1.3/Google.Apis.Script.v1.dll b/PSGSuite/lib/netstandard1.3/Google.Apis.Script.v1.dll deleted file mode 100644 index d93cf0a8..00000000 Binary files a/PSGSuite/lib/netstandard1.3/Google.Apis.Script.v1.dll and /dev/null differ diff --git a/PSGSuite/lib/netstandard1.3/Google.Apis.Sheets.v4.dll b/PSGSuite/lib/netstandard1.3/Google.Apis.Sheets.v4.dll deleted file mode 100644 index 95443c30..00000000 Binary files a/PSGSuite/lib/netstandard1.3/Google.Apis.Sheets.v4.dll and /dev/null differ diff --git a/PSGSuite/lib/netstandard1.3/Google.Apis.Slides.v1.dll b/PSGSuite/lib/netstandard1.3/Google.Apis.Slides.v1.dll deleted file mode 100644 index 86f58bbc..00000000 Binary files a/PSGSuite/lib/netstandard1.3/Google.Apis.Slides.v1.dll and /dev/null differ diff --git a/PSGSuite/lib/netstandard1.3/Google.Apis.Tasks.v1.dll b/PSGSuite/lib/netstandard1.3/Google.Apis.Tasks.v1.dll deleted file mode 100644 index e1de977e..00000000 Binary files a/PSGSuite/lib/netstandard1.3/Google.Apis.Tasks.v1.dll and /dev/null differ diff --git a/PSGSuite/lib/netstandard1.3/Google.Apis.Urlshortener.v1.dll b/PSGSuite/lib/netstandard1.3/Google.Apis.Urlshortener.v1.dll deleted file mode 100644 index 69ba0c3b..00000000 Binary files a/PSGSuite/lib/netstandard1.3/Google.Apis.Urlshortener.v1.dll and /dev/null differ diff --git a/PSGSuite/lib/netstandard1.3/Google.Apis.dll b/PSGSuite/lib/netstandard1.3/Google.Apis.dll deleted file mode 100644 index 6672f21f..00000000 Binary files a/PSGSuite/lib/netstandard1.3/Google.Apis.dll and /dev/null differ diff --git a/PSGSuite/lib/netstandard1.3/MimeKit.dll b/PSGSuite/lib/netstandard1.3/MimeKit.dll deleted file mode 100644 index 351367b9..00000000 Binary files a/PSGSuite/lib/netstandard1.3/MimeKit.dll and /dev/null differ diff --git a/PSGSuite/lib/netstandard1.3/Newtonsoft.Json.dll b/PSGSuite/lib/netstandard1.3/Newtonsoft.Json.dll deleted file mode 100644 index 96725e64..00000000 Binary files a/PSGSuite/lib/netstandard1.3/Newtonsoft.Json.dll and /dev/null differ diff --git a/README.md b/README.md index 003509cc..5ef22bca 100644 --- a/README.md +++ b/README.md @@ -143,46 +143,12 @@ Update-GSSheetValue Export-GSSheet [Full CHANGELOG here](https://github.com/scrthq/PSGSuite/blob/master/CHANGELOG.md) -#### 2.26.4 +#### 2.27.0 -* [Issue #177](https://github.com/scrthq/PSGSuite/issues/177) - _Thanks, [@WJurecki](https://github.com/WJurecki)!_ - * Fixed: `Fields` parameter `Get-GSDriveFileList` would not set correctly with the default fields value, breaking the expected experience. Restored the same functionality - -#### 2.26.3 - -* [Issue #182](https://github.com/scrthq/PSGSuite/issues/182) - _Thanks, [@aitcriver](https://github.com/aitcriver)!_ - * Added: `FileOrganizer` role to `ValidateSet` for parameter `Role` on function `Add-GSDrivePermission` - -#### 2.26.2 - -* [Issue #177](https://github.com/scrthq/PSGSuite/issues/177) - * Added: `Fields` parameter to `Get-GSDriveFileList` -* [Issue #178](https://github.com/scrthq/PSGSuite/issues/178) - * Fixed: `Start-GSDriveFileUpload` failing on PowerShell 4.0 -* [Issue #179](https://github.com/scrthq/PSGSuite/issues/179) - * Added: `Ims` parameter to both `New-GSUser` and `Update-GSUser` - * Added: `Add-GSUserIm` function to create correct type for new `Ims` parameter. -* Miscellaneous - * Added: `Clear-PSGSuiteServiceCache` to clear the cache and dispose of any remaining open web clients. - * Improved overall service caching. - * Added: Support for `Cloud-Identity` licenses for `Get-GSUserLicense` - * Added: `OutputType` for all applicable Helper functions (i.e. `Add-GSUserIm`) - -#### 2.26.1 - -* [Issue #172](https://github.com/scrthq/PSGSuite/issues/172) - * Fixed: `New-GoogleService` now using `New-Object` to prevent `[Google.Apis.Util.Store.FileDataStore]::new()` constructor issues in PowerShell 4. -* [Issue #173](https://github.com/scrthq/PSGSuite/issues/173) - * Added: `FolderColorRgb` parameter to `New-GSDriveFile` and `Update-GSDriveFile` to enable setting the color of a folder in Drive - _Thanks, [@WJurecki](https://github.com/WJurecki)!_ -* [PR #174](https://github.com/scrthq/PSGSuite/pull/174) - _Thanks, [@WJurecki](https://github.com/WJurecki)!_ - * Fixed: `Get-GSDriveFileList` filter concatenation so it joins multiple filters with ` and ` instead of just a space ` `. - -#### 2.26.0 - -* [Issue #169](https://github.com/scrthq/PSGSuite/issues/169) - * Fixed: `Get-GSGmailMessage` fails to download attachments containing invalid characters (e.g. `:`) -* [Issue #168](https://github.com/scrthq/PSGSuite/issues/168) - * Added: `Add-GSUserLocation` - * Updated: `New-GSUser` and `Update-GSUser` to add in Location support +* [Issue #185](https://github.com/scrthq/PSGSuite/issues/185) + * Fixed: `Get-GSGroup -Where_IsAMember $member` no longer errors. +* [Issue #186](https://github.com/scrthq/PSGSuite/issues/186) + * Added: `Test-GSGroupMembership` to map to the [hasMember method](https://developers.google.com/admin-sdk/directory/v1/reference/members/hasMember). * Miscellaneous - * Improved pipeline support for the `User` parameter across all pertinent functions, i.e. Drive, Calendar, Gmail, Sheets & Tasks APIs. + * Improved build process to auto-update NuGet dependencies. + * Added new private function `Resolve-Email` to convert a name-part or the case-sensitive `me` to the full email address accordingly. diff --git a/build.ps1 b/build.ps1 index 0372dfb5..b6cc6c78 100644 --- a/build.ps1 +++ b/build.ps1 @@ -13,6 +13,45 @@ param( [switch]$Force ) +$env:BuildProjectName = 'PSGSuite' +$env:_BuildStart = Get-Date -Format 'o' +$env:BuildScriptPath = $PSScriptRoot + +. ([System.IO.Path]::Combine($PSScriptRoot,"ci","AzurePipelinesHelpers.ps1")) + +Add-EnvironmentSummary "Build started" + +Set-BuildVariables + +Add-Heading "Setting package feeds" + +$modHash = @{ + PackageManagement = '1.3.1' + PowerShellGet = '2.1.2' +} +foreach ($module in $modHash.Keys | Sort-Object) { + Write-BuildLog "Updating $module module if needed" + if ($null -eq (Get-Module $module -ListAvailable | Where-Object {[System.Version]$_.Version -ge [System.Version]($modHash[$module])})) { + Write-BuildLog "$module is below the minimum required version! Updating" + Install-Module $module -MinimumVersion $modHash[$module] -Force -AllowClobber -SkipPublisherCheck -Scope CurrentUser -Verbose:$false + } +} + +Invoke-CommandWithLog {Get-PackageProvider -Name Nuget -ForceBootstrap -Verbose:$false} +Invoke-CommandWithLog {Set-PSRepository -Name PSGallery -InstallationPolicy Trusted -Verbose:$false} +Invoke-CommandWithLog {$PSDefaultParameterValues = @{ + '*-Module:Verbose' = $false + 'Import-Module:ErrorAction' = 'Stop' + 'Import-Module:Force' = $true + 'Import-Module:Verbose' = $false + 'Install-Module:AllowClobber' = $true + 'Install-Module:ErrorAction' = 'Stop' + 'Install-Module:Force' = $true + 'Install-Module:Scope' = 'CurrentUser' + 'Install-Module:Verbose' = $false +}} + +<# # build/init script borrowed from PoshBot x Brandon Olin function Resolve-Module { @@ -83,6 +122,7 @@ function Resolve-Module { } } } +#> $update = @{} $verbose = @{} @@ -94,12 +134,16 @@ if ($PSBoundParameters.ContainsKey('Verbose')) { } if ($Help) { + Add-Heading "Getting help" + Write-BuildLog -c '"psake" | Resolve-Module @update -Verbose' 'psake' | Resolve-Module @update -Verbose + Write-BuildLog "psake script tasks:" Get-PSakeScriptTasks -buildFile "$PSScriptRoot\psake.ps1" | Sort-Object -Property Name | Format-Table -Property Name, Description, Alias, DependsOn } else { + Add-Heading "Finalizing build prerequisites" if ( $Task -eq 'Deploy' -and -not $Force -and ( $ENV:BUILD_BUILDURI -notlike 'vstfs:*' -or @@ -132,21 +176,17 @@ else { " + NuGet API key is not null : $($null -ne $env:NugetApiKey)`n" + " + Commit message matches '!deploy' : $($env:BUILD_SOURCEVERSIONMESSAGE -match '!deploy') [$env:BUILD_SOURCEVERSIONMESSAGE]"| Write-Host -ForegroundColor Green } + <# if (-not (Get-Module BuildHelpers -ListAvailable | Where-Object {$_.Version -eq '2.0.1'})) { Write-Verbose "Installing BuildHelpers v2.0.1" -Verbose Install-Module 'BuildHelpers' -RequiredVersion 2.0.1 -Scope CurrentUser -Repository PSGallery -AllowClobber -SkipPublisherCheck -Force } Write-Verbose "Importing BuildHelpers v2.0.1" -Verbose Import-Module 'BuildHelpers' -RequiredVersion 2.0.1 + #> + Write-BuildLog "Resolving necessary modules" 'psake' | Resolve-Module @update -Verbose - Set-BuildEnvironment -Force - Write-Host -ForegroundColor Green "Modules successfully resolved..." - Write-Host -ForegroundColor Green "Invoking psake with task list: [ $($Task -join ', ') ]`n" - $psakeParams = @{ - nologo = $true - buildFile = "$PSScriptRoot\psake.ps1" - taskList = $Task - } + Write-BuildLog "Modules successfully resolved" if ($Task -eq 'TestOnly') { $global:ExcludeTag = @('Module') } @@ -159,10 +199,18 @@ else { else { $global:ForceDeploy = $false } + Add-Heading "Invoking psake with task list: [ $($Task -join ', ') ]" + $psakeParams = @{ + nologo = $true + buildFile = "$PSScriptRoot\psake.ps1" + taskList = $Task + } Invoke-psake @psakeParams @verbose if (($Task -contains 'Import' -or $Task -contains 'Test') -and $psake.build_success) { + Add-Heading "Importing $env:BuildProjectName to local scope" Import-Module ([System.IO.Path]::Combine($env:BHBuildOutput,$env:BHProjectName)) -Verbose:$false } + Add-EnvironmentSummary "Build finished" exit ( [int]( -not $psake.build_success ) ) } } diff --git a/ci/AzurePipelinesHelpers.ps1 b/ci/AzurePipelinesHelpers.ps1 new file mode 100644 index 00000000..d828a46a --- /dev/null +++ b/ci/AzurePipelinesHelpers.ps1 @@ -0,0 +1,428 @@ +New-Variable -Name IsCI -Value $($IsCI -or (Test-Path Env:\TF_BUILD)) -Scope Global -Force -Option AllScope + +if ($false) { + Write-Host "##[info] This is an info test!" + Write-Host "##[section] This is colored green!" + Write-Host "##[command] This is colored blue!" + Write-Host "##[debug] This is colored purple!" + Write-Host "##[warning] This is colored orange!" + Write-Host "##vso[task.logissue type=warning;]This is colored orange - task.logissue!" + Write-Host "##[error] This is colored red!" + Write-Host "##vso[task.logissue type=error;]This is colored red - task.logissue!" +} + +function Install-NuGetDependencies { + [CmdletBinding()] + Param ( + [parameter()] + [String[]] + $Destination, + [parameter()] + [String[]] + $AddlSearchString + ) + try { + Import-Module PackageManagement -Force + $dllStgPath = Join-Path $PSScriptRoot "NuGetStaging" + $packagesToInstall = Get-Content (Join-Path $PSScriptRoot "NuGetDependencies.json") -Raw | ConvertFrom-Json | Sort-Object BaseName + if (-not (Test-Path $dllStgPath)) { + New-Item $dllStgPath -Force -ItemType Directory | Out-Null + } + $nugHash = @{} + foreach ($search in $AddlSearchString) { + Write-BuildLog "Finding NuGet packages matching SearchString: $search" + Find-Package $search -Source nuget.org -AllowPrereleaseVersions:$false -Verbose | Where-Object {$_.Name -in $packagesToInstall.BaseName} | ForEach-Object { + Write-BuildLog "Matched package: $($_.Name)" + $nugHash[$_.Name] = $_ + } + } + if ($nugHash.Keys.Count) { + . ([System.IO.Path]::Combine($PSScriptRoot,"UpdateNuGetDependenciesJson.ps1")) + } + foreach ($inst in $packagesToInstall) { + try { + $pkg = if ($nugHash.ContainsKey($inst.BaseName)) { + $nugHash[$inst.BaseName] + } + else { + [PSCustomObject]@{ + Name = $inst.BaseName + Version = $inst.LatestVersion + TagId = $inst.BaseName + '#' + $inst.LatestVersion + } + } + Write-BuildLog ("[{0}.{1}] Downloading latest package from NuGet" -f $pkg.Name,$pkg.Version) + $extPath = [System.IO.Path]::Combine($dllStgPath,"$($pkg.Name.ToLower().TrimEnd('.dll')).$($pkg.Version)") + if (Test-Path ($extPath)) { + Remove-Item $extPath -Recurse -Force + } + New-Item -Path $extPath -ItemType Directory -ErrorAction SilentlyContinue | Out-Null + $zipPath = $extPath.TrimEnd('.dll') + '.zip' + if (Test-Path ($zipPath)) { + Remove-Item $zipPath -Force + } + + $pkgUrl = 'https://www.nuget.org/api/v2/package/'+ ($pkg.TagId.Replace('#','/')) + $i = 0 + do { + Invoke-WebRequest -Uri $pkgUrl -OutFile $zipPath + $i++ + } + until ((Test-Path $zipPath) -or $i -ge 5) + if ($i -ge 5) { + throw "Failed to download NuGet package from URL: $pkgUrl" + } + Unblock-File $zipPath + Add-Type -AssemblyName System.IO.Compression + [System.IO.Compression.ZipFile]::ExtractToDirectory($zipPath,$extPath) + foreach ($dest in $Destination) { + foreach ($target in @('net45','netstandard1.3')) { + $targetPath = [System.IO.Path]::Combine($dest,'lib',$target) + if (-not (Test-Path $targetPath)) { + New-Item -Path $targetPath -ItemType Directory -ErrorAction SilentlyContinue | Out-Null + } + $sourcePath = if ($pkg.Name -eq 'BouncyCastle.Crypto.dll') { + [System.IO.Path]::Combine($extPath,'lib') + } + else { + [System.IO.Path]::Combine($extPath,'lib',$target) + } + if (Test-Path $sourcePath) { + Get-ChildItem $sourcePath -Filter '*.dll' | Copy-Item -Destination $targetPath -Force -Verbose + } + else { + Write-BuildError "$($pkg.Name) was not downloaded successfully from NuGet!" -ErrorAction Stop + exit 1 + } + } + } + } + catch { + Write-Warning "Error when trying [$($inst.BaseName)]: $($_.Exception.Message)" + } + finally { + if (Test-Path ($zipPath)) { + Remove-Item $zipPath -Force + } + if (Test-Path ($extPath)) { + Remove-Item $extPath -Recurse -Force + } + } + } + } + finally { + if (Test-Path $dllStgPath) { + Remove-Item $dllStgPath -Recurse -Force + } + } +} + +function Resolve-Module { + [Cmdletbinding()] + param ( + [Parameter(Mandatory, ValueFromPipeline)] + [string[]]$Name, + + [switch]$UpdateModules + ) + Begin { + $PSDefaultParameterValues = @{ + '*-Module:Verbose' = $false + 'Import-Module:ErrorAction' = 'Stop' + 'Import-Module:Force' = $true + 'Import-Module:Verbose' = $false + 'Install-Module:AllowClobber' = $true + 'Install-Module:ErrorAction' = 'Stop' + 'Install-Module:Force' = $true + 'Install-Module:Scope' = 'CurrentUser' + 'Install-Module:Verbose' = $false + } + } + process { + foreach ($moduleName in $Name) { + $versionToImport = '' + + Write-Verbose -Message "Resolving Module [$($moduleName)]" + if ($Module = Get-Module -Name $moduleName -ListAvailable -Verbose:$false) { + # Determine latest version on PSGallery and warn us if we're out of date + $latestLocalVersion = ($Module | Measure-Object -Property Version -Maximum).Maximum + $latestGalleryVersion = (Find-Module -Name $moduleName -Repository PSGallery | + Measure-Object -Property Version -Maximum).Maximum + + # Out we out of date? + if ($latestLocalVersion -lt $latestGalleryVersion) { + if ($UpdateModules) { + Write-Verbose -Message "$($moduleName) installed version [$($latestLocalVersion.ToString())] is outdated. Installing gallery version [$($latestGalleryVersion.ToString())]" + if ($UpdateModules) { + Install-Module -Name $moduleName -RequiredVersion $latestGalleryVersion + $versionToImport = $latestGalleryVersion + } + } else { + Write-Warning "$($moduleName) is out of date. Latest version on PSGallery is [$latestGalleryVersion]. To update, use the -UpdateModules switch." + } + } else { + $versionToImport = $latestLocalVersion + } + } else { + Write-Verbose -Message "[$($moduleName)] missing. Installing..." + Install-Module -Name $moduleName -Repository PSGallery + $versionToImport = (Get-Module -Name $moduleName -ListAvailable | Measure-Object -Property Version -Maximum).Maximum + } + + Write-Verbose -Message "$($moduleName) installed. Importing..." + if (-not [string]::IsNullOrEmpty($versionToImport)) { + Import-module -Name $moduleName -RequiredVersion $versionToImport + } else { + Import-module -Name $moduleName + } + } + } +} + +function Get-PsakeTaskSectionFormatter { + $sb = { + param($String) + "$((Add-Heading "Executing task: {0}" -PassThru) -join "`n")" -f $String + } + return $sb +} + +function Add-Heading { + param( + [parameter(Position = 0,ValueFromRemainingArguments)] + [String] + $Title, + [Switch] + $Passthru + ) + $date = "[$((Get-Date).ToString("HH:mm:ss")) +$(((Get-Date) - (Get-Date $env:_BuildStart)).ToString())]" + $msgList = @( + '' + "##[section] $date $Title" + ) + if ($Passthru) { + $msgList + } + else { + $msgList | Write-Host -ForegroundColor Cyan + } +} +Set-Alias -Name Heading -Value Add-Heading -Force + +function Add-EnvironmentSummary { + param( + [parameter(Position = 0,ValueFromRemainingArguments)] + [String] + $State + ) + Add-Heading Build Environment Summary + @( + "Project : $env:BuildProjectName" + "State : $State" + "Engine : PowerShell $($PSVersionTable.PSVersion.ToString())" + "Host OS : $(if($PSVersionTable.PSVersion.Major -le 5 -or $IsWindows){"Windows"}elseif($IsLinux){"Linux"}elseif($IsMacOS){"macOS"}else{"[UNKNOWN]"})" + "PWD : $PWD" + '' + ) | Write-Host +} +Set-Alias -Name Summary -Value Add-EnvironmentSummary -Force + +function Write-BuildWarning { + param( + [parameter(Mandatory,Position = 0,ValueFromRemainingArguments,ValueFromPipeline)] + [System.Object] + $Message + ) + Process { + Write-Warning $Message + if ($IsCI) { + Write-Host "##vso[task.logissue type=warning;]$Message" + } + else { + } + } +} + +function Write-BuildError { + param( + [parameter(Mandatory,Position = 0,ValueFromRemainingArguments,ValueFromPipeline)] + [System.Object] + $Message + ) + Process { + Write-Error $Message + if ($IsCI) { + Write-Host "##vso[task.logissue type=error;]$Message" + } + } +} + +function Write-BuildLog { + [CmdletBinding()] + param( + [parameter(Mandatory,Position = 0,ValueFromRemainingArguments,ValueFromPipeline)] + [System.Object] + $Message, + [parameter()] + [Alias('c','Command')] + [Switch] + $Cmd, + [parameter()] + [Alias('w')] + [Switch] + $Warning, + [parameter()] + [Alias('s','e')] + [Switch] + $Severe, + [parameter()] + [Alias('x','nd','n')] + [Switch] + $Clean + ) + Begin { + if ($PSBoundParameters.ContainsKey('Debug') -and $PSBoundParameters['Debug'] -eq $true) { + $fg = 'Yellow' + $lvl = '##[debug] ' + } + elseif ($PSBoundParameters.ContainsKey('Verbose') -and $PSBoundParameters['Verbose'] -eq $true) { + $fg = if ($Host.UI.RawUI.ForegroundColor -eq 'Gray') { + 'White' + } + else { + 'Gray' + } + $lvl = '##[verbose] ' + } + elseif ($Severe) { + $fg = 'Red' + $lvl = '##[error] ' + } + elseif ($Warning) { + $fg = 'Yellow' + $lvl = '##[warning] ' + } + elseif ($Cmd) { + $fg = 'Magenta' + $lvl = '##[command] ' + } + else { + $fg = if ($Host.UI.RawUI.ForegroundColor -eq 'Gray') { + 'White' + } + else { + 'Gray' + } + $lvl = '##[info] ' + } + } + Process { + $fmtMsg = if ($Clean){ + $Message -split "[\r\n]" | Where-Object {$_} | ForEach-Object { + $lvl + $_ + } + } + else { + $date = "[$((Get-Date).ToString("HH:mm:ss")) +$(((Get-Date) - (Get-Date $env:_BuildStart)).ToString())] " + if ($Cmd) { + $i = 0 + $Message -split "[\r\n]" | Where-Object {$_} | ForEach-Object { + if ($i -eq 0) { + $startIndex = if ($_ -match "^\s+") { + $new = $_ -replace "^\s+" + $_.Length - $new.Length + } + else { + 0 + } + $tag = 'PS > ' + } + else { + $tag = ' >> ' + } + $finalIndex = if ($startIndex -lt $_.Length) { + $startIndex + } + else{ + 0 + } + $lvl + $date + $tag + ([String]$_).Substring($finalIndex) + $i++ + } + } + else { + $Message -split "[\r\n]" | Where-Object {$_} | ForEach-Object { + $lvl + $date + $_ + } + } + } + Write-Host -ForegroundColor $fg $($fmtMsg -join "`n") + } +} +Set-Alias -Name Log -Value Write-BuildLog -Force + +function Invoke-CommandWithLog { + [CmdletBinding()] + Param ( + [parameter(Mandatory,Position=0)] + [ScriptBlock] + $ScriptBlock + ) + Write-BuildLog -Command ($ScriptBlock.ToString() -join "`n") + $ScriptBlock.Invoke() +} + +function Set-EnvironmentVariable { + param( + [parameter(Position = 0)] + [String] + $Name, + [parameter(Position = 1,ValueFromRemainingArguments)] + [String[]] + $Value + ) + $fullVal = $Value -join " " + Write-BuildLog "Setting env variable '$Name' to '$fullVal'" + Set-Item -Path Env:\$Name -Value $fullVal -Force + if ($IsCI) { + "##vso[task.setvariable variable=$Name]$fullVal" | Write-Host + } +} +Set-Alias -Name SetEnv -Value Set-EnvironmentVariable -Force + +function Set-BuildVariables { + $gitVars = if ($IsCI) { + @{ + BHBranchName = $env:BUILD_SOURCEBRANCHNAME + BHPSModuleManifest = "$env:BuildScriptPath\$env:BuildProjectName\$env:BuildProjectName.psd1" + BHPSModulePath = "$env:BuildScriptPath\$env:BuildProjectName" + BHProjectName = $env:BuildProjectName + BHBuildNumber = $env:BUILD_BUILDNUMBER + BHModulePath = "$env:BuildScriptPath\$env:BuildProjectName" + BHBuildOutput = "$env:BuildScriptPath\BuildOutput" + BHBuildSystem = 'VSTS' + BHProjectPath = $env:SYSTEM_DEFAULTWORKINGDIRECTORY + BHCommitMessage = $env:BUILD_SOURCEVERSIONMESSAGE + } + } + else { + @{ + BHBranchName = $((git rev-parse --abbrev-ref HEAD).Trim()) + BHPSModuleManifest = "$env:BuildScriptPath\$env:BuildProjectName\$env:BuildProjectName.psd1" + BHPSModulePath = "$env:BuildScriptPath\$env:BuildProjectName" + BHProjectName = $env:BuildProjectName + BHBuildNumber = 'Unknown' + BHModulePath = "$env:BuildScriptPath\$env:BuildProjectName" + BHBuildOutput = "$env:BuildScriptPath\BuildOutput" + BHBuildSystem = [System.Environment]::MachineName + BHProjectPath = $env:BuildScriptPath + BHCommitMessage = $((git log --format=%B -n 1).Trim()) + } + } + Add-Heading 'Setting environment variables if needed' + foreach ($var in $gitVars.Keys) { + if (-not (Test-Path Env:\$var)) { + Set-EnvironmentVariable $var $gitVars[$var] + } + } +} diff --git a/ci/NuGetDependencies.json b/ci/NuGetDependencies.json new file mode 100644 index 00000000..81781a8b --- /dev/null +++ b/ci/NuGetDependencies.json @@ -0,0 +1,164 @@ +[ + { + "Name": "BouncyCastle.Crypto.dll", + "BaseName": "BouncyCastle.Crypto.dll", + "Target": "1.8.1", + "LatestVersion": "1.8.1" + }, + { + "Name": "Google.Apis.dll", + "BaseName": "Google.Apis", + "Target": "Latest", + "LatestVersion": "1.40.0" + }, + { + "Name": "Google.Apis.Admin.DataTransfer.datatransfer_v1.dll", + "BaseName": "Google.Apis.Admin.DataTransfer.datatransfer_v1", + "Target": "Latest", + "LatestVersion": "1.40.0.418" + }, + { + "Name": "Google.Apis.Admin.Directory.directory_v1.dll", + "BaseName": "Google.Apis.Admin.Directory.directory_v1", + "Target": "Latest", + "LatestVersion": "1.40.0.1505" + }, + { + "Name": "Google.Apis.Admin.Reports.reports_v1.dll", + "BaseName": "Google.Apis.Admin.Reports.reports_v1", + "Target": "Latest", + "LatestVersion": "1.40.0.1578" + }, + { + "Name": "Google.Apis.Auth.dll", + "BaseName": "Google.Apis.Auth", + "Target": "Latest", + "LatestVersion": "1.40.0" + }, + { + "Name": "Google.Apis.Auth.PlatformServices.dll", + "BaseName": "Google.Apis.Auth.PlatformServices", + "Target": "Latest", + "LatestVersion": "1.40.0" + }, + { + "Name": "Google.Apis.Calendar.v3.dll", + "BaseName": "Google.Apis.Calendar.v3", + "Target": "Latest", + "LatestVersion": "1.40.0.1580" + }, + { + "Name": "Google.Apis.Classroom.v1.dll", + "BaseName": "Google.Apis.Classroom.v1", + "Target": "Latest", + "LatestVersion": "1.40.0.1587" + }, + { + "Name": "Google.Apis.Core.dll", + "BaseName": "Google.Apis.Core", + "Target": "Latest", + "LatestVersion": "1.40.0" + }, + { + "Name": "Google.Apis.Docs.v1.dll", + "BaseName": "Google.Apis.Docs.v1", + "Target": "Latest", + "LatestVersion": "1.40.0.1581" + }, + { + "Name": "Google.Apis.Drive.v3.dll", + "BaseName": "Google.Apis.Drive.v3", + "Target": "Latest", + "LatestVersion": "1.40.0.1587" + }, + { + "Name": "Google.Apis.DriveActivity.v2.dll", + "BaseName": "Google.Apis.DriveActivity.v2", + "Target": "Latest", + "LatestVersion": "1.40.0.1589" + }, + { + "Name": "Google.Apis.Gmail.v1.dll", + "BaseName": "Google.Apis.Gmail.v1", + "Target": "Latest", + "LatestVersion": "1.40.0.1572" + }, + { + "Name": "Google.Apis.Groupssettings.v1.dll", + "BaseName": "Google.Apis.Groupssettings.v1", + "Target": "Latest", + "LatestVersion": "1.40.0.1534" + }, + { + "Name": "Google.Apis.HangoutsChat.v1.dll", + "BaseName": "Google.Apis.HangoutsChat.v1", + "Target": "Latest", + "LatestVersion": "1.40.0.1583" + }, + { + "Name": "Google.Apis.Licensing.v1.dll", + "BaseName": "Google.Apis.Licensing.v1", + "Target": "Latest", + "LatestVersion": "1.40.0.774" + }, + { + "Name": "Google.Apis.Oauth2.v2.dll", + "BaseName": "Google.Apis.Oauth2.v2", + "Target": "Latest", + "LatestVersion": "1.40.0.1532" + }, + { + "Name": "Google.Apis.PeopleService.v1.dll", + "BaseName": "Google.Apis.PeopleService.v1", + "Target": "Latest", + "LatestVersion": "1.40.0.1588" + }, + { + "Name": "Google.Apis.PlatformServices.dll", + "BaseName": "Google.Apis.PlatformServices", + "Target": "Latest", + "LatestVersion": "1.40.0" + }, + { + "Name": "Google.Apis.Script.v1.dll", + "BaseName": "Google.Apis.Script.v1", + "Target": "Latest", + "LatestVersion": "1.40.0.1589" + }, + { + "Name": "Google.Apis.Sheets.v4.dll", + "BaseName": "Google.Apis.Sheets.v4", + "Target": "Latest", + "LatestVersion": "1.40.0.1588" + }, + { + "Name": "Google.Apis.Slides.v1.dll", + "BaseName": "Google.Apis.Slides.v1", + "Target": "Latest", + "LatestVersion": "1.40.0.1579" + }, + { + "Name": "Google.Apis.Tasks.v1.dll", + "BaseName": "Google.Apis.Tasks.v1", + "Target": "Latest", + "LatestVersion": "1.40.0.1513" + }, + { + "Name": "Google.Apis.Urlshortener.v1.dll", + "BaseName": "Google.Apis.Urlshortener.v1", + "Target": "Latest", + "LatestVersion": "1.40.0.138" + }, + { + "Name": "MimeKit.dll", + "BaseName": "MimeKit", + "Target": "1.10.1.0", + "LatestVersion": "1.10.1.0" + }, + { + "Name": "Newtonsoft.Json.dll", + "BaseName": "Newtonsoft.Json", + "Target": "10.0.3", + "LatestVersion": "10.0.3" + } +] diff --git a/ci/UpdateNuGetDependenciesJson.ps1 b/ci/UpdateNuGetDependenciesJson.ps1 new file mode 100644 index 00000000..46bfaf66 --- /dev/null +++ b/ci/UpdateNuGetDependenciesJson.ps1 @@ -0,0 +1,46 @@ +if ($items = Get-ChildItem (Resolve-Path $PSScriptRoot\..\BuildOutput\PSGSuite\*\lib\net45 -ErrorAction SilentlyContinue).Path -Filter '*.dll') { + $items | + #Where-Object | + Sort-Object BaseName | + Select-Object Name, + @{ + N = 'BaseName' + E = { + if ($_.BaseName -eq 'BouncyCastle.Crypto') { + 'BouncyCastle.Crypto.dll' + } + else { + $_.BaseName + } + } + }, + @{ + N='Target' + E={ + if ($_.BaseName -match 'Google') { + 'Latest' + } + else { + switch ($_.BaseName) { + 'BouncyCastle.Crypto' { + '1.8.1' + } + 'MimeKit' { + '1.10.1.0' + } + 'Newtonsoft.Json' { + '10.0.3' + } + } + } + } + }, + @{ + N='LatestVersion' + E={ + [System.Diagnostics.FileVersionInfo]::GetVersionInfo($_.FullName).ProductVersion + } + } | + ConvertTo-Json | + Set-Content (Join-Path $PSScriptRoot 'NuGetDependencies.json') -Force +} diff --git a/psake.ps1 b/psake.ps1 index 49d1c643..8cf3ca88 100644 --- a/psake.ps1 +++ b/psake.ps1 @@ -9,6 +9,7 @@ Properties { } $ProjectRoot = $pwd.Path } + $moduleName = "PSGSuite" $sut = $env:BHModulePath $tests = "$projectRoot\Tests" $Timestamp = Get-Date -Uformat "%Y%m%d-%H%M%S" @@ -20,12 +21,21 @@ Properties { $manifest = Import-PowerShellDataFile -Path $env:BHPSModuleManifest $outputModVerDir = Join-Path -Path $outputModDir -ChildPath $manifest.ModuleVersion $pathSeperator = [IO.Path]::PathSeparator + $NuGetSearchStrings = @( + "Google.Apis*" + ) $Verbose = @{} if ($ENV:BHCommitMessage -match "!verbose") { $Verbose = @{Verbose = $True} } } +. ([System.IO.Path]::Combine($PSScriptRoot,"ci","AzurePipelinesHelpers.ps1")) + +Set-BuildVariables + +FormatTaskName (Get-PsakeTaskSectionFormatter) + #Task Default -Depends Init,Test,Build,Deploy task default -depends Test @@ -34,12 +44,12 @@ task Skip { } task Init { - "`nSTATUS: Testing with PowerShell $psVersion" - "Build System Details:" - Get-Item ENV:BH* - Get-Item ENV:BUILD_* - "`n" Set-Location $ProjectRoot + Write-BuildLog "Build System Details:" + Write-BuildLog "$((Get-ChildItem Env: | Where-Object {$_.Name -match "^(BUILD_|SYSTEM_|BH)"} | Sort-Object Name | Format-Table Name,Value -AutoSize | Out-String).Trim())" + if ($env:BHProjectName -cne $moduleName) { + $env:BHProjectName = $moduleName + } 'Configuration', 'Pester' | Foreach-Object { Install-Module -Name $_ -Repository PSGallery -Scope CurrentUser -AllowClobber -SkipPublisherCheck -Confirm:$false -ErrorAction Stop -Force @@ -55,10 +65,17 @@ task Clean -depends Init { Remove-Module -Name $env:BHProjectName -Force -ErrorAction SilentlyContinue if (Test-Path -Path $outputDir) { - Get-ChildItem -Path $outputDir -Recurse -File | Where-Object {$_.BaseName -eq $env:BHProjectName -or $_.Name -like "Test*.xml"} | Remove-Item -Force -Recurse + Get-ChildItem -Path $outputDir -Recurse | Sort-Object {$_.FullName.Length} -Descending | ForEach-Object { + try { + Remove-Item $_.FullName -Force -Recurse + } + catch { + Write-Warning "Unable to delete: '$($_.FullName)'" + } + } } else { - New-Item -Path $outputDir -ItemType Directory > $null + New-Item -Path $outputDir -ItemType Directory | Out-Null } " Cleaned previous output directory [$outputDir]" } -description 'Cleans module output directory' @@ -66,12 +83,13 @@ task Clean -depends Init { task Compile -depends Clean { # Create module output directory $functionsToExport = @() + $sutLib = [System.IO.Path]::Combine($sut,'lib') $aliasesToExport = (. $sut\Aliases\PSGSuite.Aliases.ps1).Keys $modDir = New-Item -Path $outputModDir -ItemType Directory -ErrorAction SilentlyContinue - New-Item -Path $outputModVerDir -ItemType Directory -ErrorAction SilentlyContinue > $null + New-Item -Path $outputModVerDir -ItemType Directory -ErrorAction SilentlyContinue | Out-Null # Append items to psm1 - Write-Verbose -Message 'Creating psm1...' + Write-BuildLog 'Creating psm1...' $psm1 = Copy-Item -Path (Join-Path -Path $sut -ChildPath 'PSGSuite.psm1') -Destination (Join-Path -Path $outputModVerDir -ChildPath "$($ENV:BHProjectName).psm1") -PassThru Get-ChildItem -Path (Join-Path -Path $sut -ChildPath 'Private') -Recurse -File | ForEach-Object { @@ -82,8 +100,11 @@ task Compile -depends Clean { $functionsToExport += $_.BaseName } - New-Item -Path "$outputModVerDir\lib" -ItemType Directory -ErrorAction SilentlyContinue > $null - Copy-Item -Path "$sut\lib\*" -Destination "$outputModVerDir\lib" -Recurse -ErrorAction SilentlyContinue + New-Item -Path "$outputModVerDir\lib" -ItemType Directory -ErrorAction SilentlyContinue | Out-Null + Invoke-CommandWithLog {Remove-Module $env:BHProjectName -ErrorAction SilentlyContinue -Force -Verbose:$false} + Write-BuildLog "Installing NuGet dependencies..." + Invoke-CommandWithLog {Install-NuGetDependencies -Destination $outputModVerDir -AddlSearchString $NuGetSearchStrings -Verbose} + $aliasHashContents = (Get-Content "$sut\Aliases\PSGSuite.Aliases.ps1" -Raw).Trim() # Set remainder of PSM1 contents