From 2486d2cc37ff983a11ab46dc8931e724f8017eab Mon Sep 17 00:00:00 2001 From: Tiberriver256 Date: Sat, 5 Mar 2016 21:54:39 -0500 Subject: [PATCH 01/34] Added size comparison When MatchSource is $False and Test-Path is $True added a webclient content-length check to compare the size in bytes of the target and destination files. This will ensure that the file is re-downloaded if the file sizes are not the same (i.e. target file has been updated, download was interrupted previously, local file was corrupted, etc.) --- DSCResources/MSFT_xRemoteFile/MSFT_xRemoteFile.psm1 | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/DSCResources/MSFT_xRemoteFile/MSFT_xRemoteFile.psm1 b/DSCResources/MSFT_xRemoteFile/MSFT_xRemoteFile.psm1 index c6568808f..b50e8c333 100644 --- a/DSCResources/MSFT_xRemoteFile/MSFT_xRemoteFile.psm1 +++ b/DSCResources/MSFT_xRemoteFile/MSFT_xRemoteFile.psm1 @@ -253,7 +253,13 @@ function Test-TargetResource } } else { Write-Debug "MatchSource is false. No need for downloading file." - $fileExists = $true + [System.Net.WebClient]$wc = [System.Net.WebClient]::New() + $wc.OpenRead($URI) + [Long]$bytes_total = $wc.ResponseHeaders["Content-Length"] + if($bytes_total -eq (Get-Item $DestinationPath).Length) + { + $fileExists = $true + } } } From 9896e2cf14eee8ae432ba563e75c07dab8c30443 Mon Sep 17 00:00:00 2001 From: Micah Rairdon Date: Mon, 7 Mar 2016 19:47:05 -0500 Subject: [PATCH 02/34] Added appropriate Write-Debug lines --- .../MSFT_xRemoteFile/MSFT_xRemoteFile.psm1 | 953 +++++++++--------- 1 file changed, 477 insertions(+), 476 deletions(-) diff --git a/DSCResources/MSFT_xRemoteFile/MSFT_xRemoteFile.psm1 b/DSCResources/MSFT_xRemoteFile/MSFT_xRemoteFile.psm1 index b50e8c333..b5dc8f738 100644 --- a/DSCResources/MSFT_xRemoteFile/MSFT_xRemoteFile.psm1 +++ b/DSCResources/MSFT_xRemoteFile/MSFT_xRemoteFile.psm1 @@ -1,482 +1,483 @@ -data localizedData -{ - # culture="en-US" - ConvertFrom-StringData @' -InvalidWebUriError=Specified URI is not valid: "{0}". Only http and https paths are accepted. -InvalidDestinationPathSchemeError=Specified DestinationPath is not valid: "{0}". DestinationPath should be absolute path. -DestinationPathIsUncError=Specified DestinationPath is not valid: "{0}". DestinationPath should be local path instead of UNC path. -DestinationPathHasInvalidCharactersError=Specified DestinationPath is not valid: "{0}". DestinationPath should be contains following characters: * ? " < > | -DestinationPathEndsWithInvalidCharacterError=Specified DestinationPath is not valid: "{0}". DestinationPath should not end with / or \\ -'@ -} - -# Path where cache will be stored. It's cleared whenever LCM gets new configuration. -$script:cacheLocation = "$env:ProgramData\Microsoft\Windows\PowerShell\Configuration\BuiltinProvCache\MSFT_xRemoteFile" - -# The Get-TargetResource function is used to fetch the status of file specified in DestinationPath on the target machine. -function Get-TargetResource -{ - [CmdletBinding()] - [OutputType([System.Collections.Hashtable])] - param - ( - [parameter(Mandatory = $true)] - [ValidateNotNullOrEmpty()] - [System.String] - $DestinationPath, - - [parameter(Mandatory = $true)] - [ValidateNotNullOrEmpty()] - [System.String] - $Uri - ) - - # Check whether DestinationPath is existing file - $fileExists = $false - $pathItemType = Get-PathItemType -path $DestinationPath - switch($pathItemType) - { - "File" { - Write-Verbose "DestinationPath: '$DestinationPath' is existing file on the machine" - $fileExists = $true - } - - "Directory" { - Write-Verbose "DestinationPath: '$DestinationPath' is existing directory on the machine" - - # If it's existing directory, let's check whether expectedDestinationPath exists - $uriFileName = Split-Path $Uri -Leaf - $expectedDestinationPath = Join-Path $DestinationPath $uriFileName - if (Test-Path $expectedDestinationPath) { - Write-Verbose "File $uriFileName exists in DestinationPath" - $fileExists = $true - } - } - - "Other" { - Write-Verbose "DestinationPath: '$DestinationPath' has unknown type: '$pathItemType'" - } - - "NotExists" { - Write-Verbose "DestinationPath: '$DestinationPath' doesn't exist on the machine" - } - } - - $ensure = "Absent" - if ($fileExists) - { - $ensure = "Present" - } - - $returnValue = @{ - DestinationPath = $DestinationPath - Ensure = $ensure - } - - $returnValue -} - -# The Set-TargetResource function is used to download file found under Uri location to DestinationPath -# Additional parameters can be specified to configure web request -function Set-TargetResource -{ - [CmdletBinding()] - param - ( - [parameter(Mandatory = $true)] - [ValidateNotNullOrEmpty()] - [System.String] - $DestinationPath, - - [parameter(Mandatory = $true)] - [ValidateNotNullOrEmpty()] - [System.String] - $Uri, - - [System.String] - $UserAgent, - - [Microsoft.Management.Infrastructure.CimInstance[]] - $Headers, - - [System.Management.Automation.PSCredential] - $Credential, - +data localizedData +{ + # culture="en-US" + ConvertFrom-StringData @' +InvalidWebUriError=Specified URI is not valid: "{0}". Only http and https paths are accepted. +InvalidDestinationPathSchemeError=Specified DestinationPath is not valid: "{0}". DestinationPath should be absolute path. +DestinationPathIsUncError=Specified DestinationPath is not valid: "{0}". DestinationPath should be local path instead of UNC path. +DestinationPathHasInvalidCharactersError=Specified DestinationPath is not valid: "{0}". DestinationPath should be contains following characters: * ? " < > | +DestinationPathEndsWithInvalidCharacterError=Specified DestinationPath is not valid: "{0}". DestinationPath should not end with / or \\ +'@ +} + +# Path where cache will be stored. It's cleared whenever LCM gets new configuration. +$script:cacheLocation = "$env:ProgramData\Microsoft\Windows\PowerShell\Configuration\BuiltinProvCache\MSFT_xRemoteFile" + +# The Get-TargetResource function is used to fetch the status of file specified in DestinationPath on the target machine. +function Get-TargetResource +{ + [CmdletBinding()] + [OutputType([System.Collections.Hashtable])] + param + ( + [parameter(Mandatory = $true)] + [ValidateNotNullOrEmpty()] + [System.String] + $DestinationPath, + + [parameter(Mandatory = $true)] + [ValidateNotNullOrEmpty()] + [System.String] + $Uri + ) + + # Check whether DestinationPath is existing file + $fileExists = $false + $pathItemType = Get-PathItemType -path $DestinationPath + switch($pathItemType) + { + "File" { + Write-Verbose "DestinationPath: '$DestinationPath' is existing file on the machine" + $fileExists = $true + } + + "Directory" { + Write-Verbose "DestinationPath: '$DestinationPath' is existing directory on the machine" + + # If it's existing directory, let's check whether expectedDestinationPath exists + $uriFileName = Split-Path $Uri -Leaf + $expectedDestinationPath = Join-Path $DestinationPath $uriFileName + if (Test-Path $expectedDestinationPath) { + Write-Verbose "File $uriFileName exists in DestinationPath" + $fileExists = $true + } + } + + "Other" { + Write-Verbose "DestinationPath: '$DestinationPath' has unknown type: '$pathItemType'" + } + + "NotExists" { + Write-Verbose "DestinationPath: '$DestinationPath' doesn't exist on the machine" + } + } + + $ensure = "Absent" + if ($fileExists) + { + $ensure = "Present" + } + + $returnValue = @{ + DestinationPath = $DestinationPath + Ensure = $ensure + } + + $returnValue +} + +# The Set-TargetResource function is used to download file found under Uri location to DestinationPath +# Additional parameters can be specified to configure web request +function Set-TargetResource +{ + [CmdletBinding()] + param + ( + [parameter(Mandatory = $true)] + [ValidateNotNullOrEmpty()] + [System.String] + $DestinationPath, + + [parameter(Mandatory = $true)] + [ValidateNotNullOrEmpty()] + [System.String] + $Uri, + + [System.String] + $UserAgent, + + [Microsoft.Management.Infrastructure.CimInstance[]] + $Headers, + + [System.Management.Automation.PSCredential] + $Credential, + [parameter(Mandatory = $false)] [System.Boolean] - $MatchSource = $true - ) - - # Validate Uri - if (!(Check-UriScheme -uri $Uri -scheme "http") -and !(Check-UriScheme -uri $Uri -scheme "https")) - { - $errorId = "UriValidationFailure"; - $errorMessage = $($LocalizedData.InvalidWebUriError) -f ${Uri} - Throw-InvalidDataException -errorId $errorId -errorMessage $errorMessage - } - - # Validate DestinationPath scheme - if (!(Check-UriScheme -uri $DestinationPath -scheme "file")) - { - $errorMessage = $($LocalizedData.InvalidDestinationPathSchemeError) -f ${DestinationPath} - Throw-InvalidDataException -errorId "DestinationPathSchemeValidationFailure" -errorMessage $errorMessage - } - - # Validate DestinationPath is not UNC path - if ($DestinationPath.StartsWith("\\")) - { - $errorMessage = $($LocalizedData.DestinationPathIsUncError) -f ${DestinationPath} - Throw-InvalidDataException -errorId "DestinationPathIsUncFailure" -errorMessage $errorMessage - } - - # Validate DestinationPath does not contain invalid characters - $invalidCharacters = '*','?','"','<','>','|' - $invalidCharacters | % { - if ($DestinationPath.Contains($_) ){ - $errorMessage = $($LocalizedData.DestinationPathHasInvalidCharactersError) -f ${DestinationPath} - Throw-InvalidDataException -errorId "DestinationPathHasInvalidCharactersError" -errorMessage $errorMessage - } - } - - # Validate DestinationPath does not end with / or \ (Invoke-WebRequest requirement) - if ($DestinationPath.EndsWith('/') -or $DestinationPath.EndsWith('\')){ - $errorMessage = $($LocalizedData.DestinationPathEndsWithInvalidCharacterError) -f ${DestinationPath} - Throw-InvalidDataException -errorId "DestinationPathEndsWithInvalidCharacterError" -errorMessage $errorMessage - } - - # Check whether DestinationPath's parent directory exists. Create if it doesn't. - $destinationPathParent = Split-Path $DestinationPath -Parent - if (!(Test-Path $destinationPathParent)) - { - New-Item -Type Directory -Path $destinationPathParent -Force - } - - # Check whether DestinationPath's leaf is an existing folder - $uriFileName = Split-Path $Uri -Leaf - if (Test-Path $DestinationPath -PathType Container) - { - $DestinationPath = Join-Path $DestinationPath $uriFileName - } - - # Remove DestinationPath and MatchSource from parameters as they are not parameters of Invoke-WebRequest - $PSBoundParameters.Remove("DestinationPath") | Out-Null; - $PSBoundParameters.Remove("MatchSource") | Out-Null; - - # Convert headers to hashtable - $PSBoundParameters.Remove("Headers") | Out-Null; - $headersHashtable = $null - - if ($Headers -ne $null) - { - $headersHashtable = Convert-KeyValuePairArrayToHashtable -array $Headers - } - - # Invoke web request - try - { - Write-Verbose "Downloading $Uri to $DestinationPath" - Invoke-WebRequest @PSBoundParameters -Headers $headersHashtable -outFile $DestinationPath - } - catch [System.OutOfMemoryException] - { - throw "Received OutOfMemoryException. Possible cause is the requested file being too big. $_" - } - catch [System.Exception] - { - throw "Invoking web request failed with error $($_.Exception.Response.StatusCode.Value__): $($_.Exception.Response.StatusDescription)" - } - - # Update cache - if (Test-Path $DestinationPath) - { - $downloadedFile = Get-Item $DestinationPath - $lastWriteTime = $downloadedFile.LastWriteTimeUtc - $inputObject = @{} - $inputObject["LastWriteTime"] = $lastWriteTime - Update-Cache -DestinationPath $DestinationPath -Uri $Uri -InputObject $inputObject - } -} - -# The Test-TargetResource function is used to validate if the DestinationPath exists on the machine. -function Test-TargetResource -{ - [CmdletBinding()] - [OutputType([System.Boolean])] - param - ( - [parameter(Mandatory = $true)] - [ValidateNotNullOrEmpty()] - [System.String] - $DestinationPath, - - [parameter(Mandatory = $true)] - [ValidateNotNullOrEmpty()] - [System.String] - $Uri, - - [System.String] - $UserAgent, - - [Microsoft.Management.Infrastructure.CimInstance[]] - $Headers, - - [System.Management.Automation.PSCredential] - $Credential, - + $MatchSource = $true + ) + + # Validate Uri + if (!(Check-UriScheme -uri $Uri -scheme "http") -and !(Check-UriScheme -uri $Uri -scheme "https")) + { + $errorId = "UriValidationFailure"; + $errorMessage = $($LocalizedData.InvalidWebUriError) -f ${Uri} + Throw-InvalidDataException -errorId $errorId -errorMessage $errorMessage + } + + # Validate DestinationPath scheme + if (!(Check-UriScheme -uri $DestinationPath -scheme "file")) + { + $errorMessage = $($LocalizedData.InvalidDestinationPathSchemeError) -f ${DestinationPath} + Throw-InvalidDataException -errorId "DestinationPathSchemeValidationFailure" -errorMessage $errorMessage + } + + # Validate DestinationPath is not UNC path + if ($DestinationPath.StartsWith("\\")) + { + $errorMessage = $($LocalizedData.DestinationPathIsUncError) -f ${DestinationPath} + Throw-InvalidDataException -errorId "DestinationPathIsUncFailure" -errorMessage $errorMessage + } + + # Validate DestinationPath does not contain invalid characters + $invalidCharacters = '*','?','"','<','>','|' + $invalidCharacters | % { + if ($DestinationPath.Contains($_) ){ + $errorMessage = $($LocalizedData.DestinationPathHasInvalidCharactersError) -f ${DestinationPath} + Throw-InvalidDataException -errorId "DestinationPathHasInvalidCharactersError" -errorMessage $errorMessage + } + } + + # Validate DestinationPath does not end with / or \ (Invoke-WebRequest requirement) + if ($DestinationPath.EndsWith('/') -or $DestinationPath.EndsWith('\')){ + $errorMessage = $($LocalizedData.DestinationPathEndsWithInvalidCharacterError) -f ${DestinationPath} + Throw-InvalidDataException -errorId "DestinationPathEndsWithInvalidCharacterError" -errorMessage $errorMessage + } + + # Check whether DestinationPath's parent directory exists. Create if it doesn't. + $destinationPathParent = Split-Path $DestinationPath -Parent + if (!(Test-Path $destinationPathParent)) + { + New-Item -Type Directory -Path $destinationPathParent -Force + } + + # Check whether DestinationPath's leaf is an existing folder + $uriFileName = Split-Path $Uri -Leaf + if (Test-Path $DestinationPath -PathType Container) + { + $DestinationPath = Join-Path $DestinationPath $uriFileName + } + + # Remove DestinationPath and MatchSource from parameters as they are not parameters of Invoke-WebRequest + $PSBoundParameters.Remove("DestinationPath") | Out-Null; + $PSBoundParameters.Remove("MatchSource") | Out-Null; + + # Convert headers to hashtable + $PSBoundParameters.Remove("Headers") | Out-Null; + $headersHashtable = $null + + if ($Headers -ne $null) + { + $headersHashtable = Convert-KeyValuePairArrayToHashtable -array $Headers + } + + # Invoke web request + try + { + Write-Verbose "Downloading $Uri to $DestinationPath" + Invoke-WebRequest @PSBoundParameters -Headers $headersHashtable -outFile $DestinationPath + } + catch [System.OutOfMemoryException] + { + throw "Received OutOfMemoryException. Possible cause is the requested file being too big. $_" + } + catch [System.Exception] + { + throw "Invoking web request failed with error $($_.Exception.Response.StatusCode.Value__): $($_.Exception.Response.StatusDescription)" + } + + # Update cache + if (Test-Path $DestinationPath) + { + $downloadedFile = Get-Item $DestinationPath + $lastWriteTime = $downloadedFile.LastWriteTimeUtc + $inputObject = @{} + $inputObject["LastWriteTime"] = $lastWriteTime + Update-Cache -DestinationPath $DestinationPath -Uri $Uri -InputObject $inputObject + } +} + +# The Test-TargetResource function is used to validate if the DestinationPath exists on the machine. +function Test-TargetResource +{ + [CmdletBinding()] + [OutputType([System.Boolean])] + param + ( + [parameter(Mandatory = $true)] + [ValidateNotNullOrEmpty()] + [System.String] + $DestinationPath, + + [parameter(Mandatory = $true)] + [ValidateNotNullOrEmpty()] + [System.String] + $Uri, + + [System.String] + $UserAgent, + + [Microsoft.Management.Infrastructure.CimInstance[]] + $Headers, + + [System.Management.Automation.PSCredential] + $Credential, + [parameter(Mandatory = $false)] [System.Boolean] - $MatchSource = $true - ) - - # Check whether DestinationPath points to existing file or directory - $fileExists = $false - $uriFileName = Split-Path $Uri -Leaf - $pathItemType = Get-PathItemType -path $DestinationPath - switch($pathItemType) - { - "File" { - Write-Debug "DestinationPath: '$DestinationPath' is existing file on the machine" - - if ($MatchSource) { - $file = Get-Item $DestinationPath - # Getting cache. It's cleared every time user runs Start-DscConfiguration - $cache = Get-Cache -DestinationPath $DestinationPath -Uri $Uri - - if ($cache -ne $null -and ($cache.LastWriteTime -eq $file.LastWriteTimeUtc)) - { - Write-Debug "Cache reflects current state. No need for downloading file." - $fileExists = $true - } - else - { - Write-Debug "Cache is empty or it doesn't reflect current state. File will be downloaded." - } - } else { - Write-Debug "MatchSource is false. No need for downloading file." + $MatchSource = $true + ) + + # Check whether DestinationPath points to existing file or directory + $fileExists = $false + $uriFileName = Split-Path $Uri -Leaf + $pathItemType = Get-PathItemType -path $DestinationPath + switch($pathItemType) + { + "File" { + Write-Debug "DestinationPath: '$DestinationPath' is existing file on the machine" + + if ($MatchSource) { + $file = Get-Item $DestinationPath + # Getting cache. It's cleared every time user runs Start-DscConfiguration + $cache = Get-Cache -DestinationPath $DestinationPath -Uri $Uri + + if ($cache -ne $null -and ($cache.LastWriteTime -eq $file.LastWriteTimeUtc)) + { + Write-Debug "Cache reflects current state. No need for downloading file." + $fileExists = $true + } + else + { + Write-Debug "Cache is empty or it doesn't reflect current state. File will be downloaded." + } + } else { + Write-Debug "Destination file size is not the same as source file. File will be downloaded." [System.Net.WebClient]$wc = [System.Net.WebClient]::New() $wc.OpenRead($URI) - [Long]$bytes_total = $wc.ResponseHeaders["Content-Length"] - if($bytes_total -eq (Get-Item $DestinationPath).Length) - { - $fileExists = $true - } - } - } - - "Directory" { - Write-Debug "DestinationPath: '$DestinationPath' is existing directory on the machine" - $expectedDestinationPath = Join-Path $DestinationPath $uriFileName - - if (Test-Path $expectedDestinationPath) { - if ($MatchSource) { - $file = Get-Item $expectedDestinationPath - $cache = Get-Cache -DestinationPath $expectedDestinationPath -Uri $Uri - if ($cache -ne $null -and ($cache.LastWriteTime -eq $file.LastWriteTimeUtc)) - { - Write-Debug "Cache reflects current state. No need for downloading file." - $fileExists = $true - } - else - { - Write-Debug "Cache is empty or it doesn't reflect current state. File will be downloaded." - } - } else { - Write-Debug "MatchSource is false. No need for downloading file." - $fileExists = $true - } - } - } - - "Other" { - Write-Debug "DestinationPath: '$DestinationPath' has unknown type: '$pathItemType'" - } - - "NotExists" { - Write-Debug "DestinationPath: '$DestinationPath' doesn't exist on the machine" - } - } - - $result = $fileExists - - $result -} - -# Throws terminating error of category InvalidData with specified errorId and errorMessage -function Throw-InvalidDataException -{ - param( - [parameter(Mandatory = $true)] - [System.String] - $errorId, - [parameter(Mandatory = $true)] - [System.String] - $errorMessage - ) - - $errorCategory = [System.Management.Automation.ErrorCategory]::InvalidData - $exception = New-Object System.InvalidOperationException $errorMessage - $errorRecord = New-Object System.Management.Automation.ErrorRecord $exception, $errorId, $errorCategory, $null - throw $errorRecord -} - -# Checks whether given URI represents specific scheme -# Most common schemes: file, http, https, ftp -# We can also specify logical expressions like: [http|https] -function Check-UriScheme -{ - param ( - [parameter(Mandatory = $true)] - [System.String] - $uri, - [parameter(Mandatory = $true)] - [System.String] - $scheme - ) - $newUri = $uri -as [System.URI] - $newUri.AbsoluteURI -ne $null -and $newUri.Scheme -match $scheme -} - -# Gets type of the item which path points to. -# Returns: File, Directory, Other or NotExists -function Get-PathItemType -{ - param ( - [parameter(Mandatory = $true)] - [System.String] - $path - ) - - $type = $null - - # Check whether path exists - if (Test-Path $path) - { - # Check type of the path - $pathItem = Get-Item $path - $pathItemType = $pathItem.GetType().Name - if ($pathItemType -eq "FileInfo") - { - $type = "File" - } - elseif ($pathItemType -eq "DirectoryInfo") - { - $type = "Directory" - } - else - { - $type = "Other" - } - } - else - { - $type = "NotExists" - } - - return $type -} - -# Converts CimInstance array of type KeyValuePair to hashtable -function Convert-KeyValuePairArrayToHashtable -{ - param ( - [parameter(Mandatory = $true)] - [Microsoft.Management.Infrastructure.CimInstance[]] - $array - ) - - $hashtable = @{} - foreach($item in $array) - { - $hashtable += @{$item.Key = $item.Value} - } - - return $hashtable -} - -# Gets cache for specific DestinationPath and Uri -function Get-Cache -{ - param ( - [parameter(Mandatory = $true)] - [ValidateNotNullOrEmpty()] - [System.String] - $DestinationPath, - - [parameter(Mandatory = $true)] - [ValidateNotNullOrEmpty()] - [System.String] - $Uri - ) - - $cacheContent = $null - $key = Get-CacheKey -DestinationPath $DestinationPath -Uri $Uri - $path = Join-Path $script:cacheLocation $key - - Write-Debug "Looking for path $path" - if(!(Test-Path $path)) - { - Write-Debug "No cache found for DestinationPath = $DestinationPath and Uri = $Uri. CacheKey = $key" - $cacheContent = $null - } - else - { - $cacheContent = Import-CliXml $path - Write-Debug "Found cache for DestinationPath = $DestinationPath and Uri = $Uri. CacheKey = $key" - } - - return $cacheContent -} - -# Creates or updates cache for specific DestinationPath and Uri -function Update-Cache -{ - param ( - [parameter(Mandatory = $true)] - [ValidateNotNullOrEmpty()] - [System.String] - $DestinationPath, - - [parameter(Mandatory = $true)] - [ValidateNotNullOrEmpty()] - [System.String] - $Uri, - - [parameter(Mandatory = $true)] - [Object] - $InputObject - ) - - $key = Get-CacheKey -DestinationPath $DestinationPath -Uri $Uri - $path = Join-Path $script:cacheLocation $key - - if(-not (Test-Path $script:cacheLocation)) - { - mkdir $script:cacheLocation | Out-Null - } - - Write-Debug "Updating cache for DestinationPath = $DestinationPath and Uri = $Uri. CacheKey = $key" - Export-CliXml -Path $path -InputObject $InputObject -Force -} - -# Returns cache key for given parameters -function Get-CacheKey -{ - param ( - [parameter(Mandatory = $true)] - [ValidateNotNullOrEmpty()] - [System.String] - $DestinationPath, - - [parameter(Mandatory = $true)] - [ValidateNotNullOrEmpty()] - [System.String] - $Uri - ) - $key = [string]::Join("", @($DestinationPath, $Uri)).GetHashCode().ToString() - return $key -} - -Export-ModuleMember -Function *-TargetResource - - - + [Long]$bytes_total = $wc.ResponseHeaders["Content-Length"] + if($bytes_total -eq (Get-Item $DestinationPath).Length) + { + Write-Debug "MatchSource is false. No need for downloading file." + $fileExists = $true + } + } + } + + "Directory" { + Write-Debug "DestinationPath: '$DestinationPath' is existing directory on the machine" + $expectedDestinationPath = Join-Path $DestinationPath $uriFileName + + if (Test-Path $expectedDestinationPath) { + if ($MatchSource) { + $file = Get-Item $expectedDestinationPath + $cache = Get-Cache -DestinationPath $expectedDestinationPath -Uri $Uri + if ($cache -ne $null -and ($cache.LastWriteTime -eq $file.LastWriteTimeUtc)) + { + Write-Debug "Cache reflects current state. No need for downloading file." + $fileExists = $true + } + else + { + Write-Debug "Cache is empty or it doesn't reflect current state. File will be downloaded." + } + } else { + Write-Debug "MatchSource is false. No need for downloading file." + $fileExists = $true + } + } + } + + "Other" { + Write-Debug "DestinationPath: '$DestinationPath' has unknown type: '$pathItemType'" + } + + "NotExists" { + Write-Debug "DestinationPath: '$DestinationPath' doesn't exist on the machine" + } + } + + $result = $fileExists + + $result +} + +# Throws terminating error of category InvalidData with specified errorId and errorMessage +function Throw-InvalidDataException +{ + param( + [parameter(Mandatory = $true)] + [System.String] + $errorId, + [parameter(Mandatory = $true)] + [System.String] + $errorMessage + ) + + $errorCategory = [System.Management.Automation.ErrorCategory]::InvalidData + $exception = New-Object System.InvalidOperationException $errorMessage + $errorRecord = New-Object System.Management.Automation.ErrorRecord $exception, $errorId, $errorCategory, $null + throw $errorRecord +} + +# Checks whether given URI represents specific scheme +# Most common schemes: file, http, https, ftp +# We can also specify logical expressions like: [http|https] +function Check-UriScheme +{ + param ( + [parameter(Mandatory = $true)] + [System.String] + $uri, + [parameter(Mandatory = $true)] + [System.String] + $scheme + ) + $newUri = $uri -as [System.URI] + $newUri.AbsoluteURI -ne $null -and $newUri.Scheme -match $scheme +} + +# Gets type of the item which path points to. +# Returns: File, Directory, Other or NotExists +function Get-PathItemType +{ + param ( + [parameter(Mandatory = $true)] + [System.String] + $path + ) + + $type = $null + + # Check whether path exists + if (Test-Path $path) + { + # Check type of the path + $pathItem = Get-Item $path + $pathItemType = $pathItem.GetType().Name + if ($pathItemType -eq "FileInfo") + { + $type = "File" + } + elseif ($pathItemType -eq "DirectoryInfo") + { + $type = "Directory" + } + else + { + $type = "Other" + } + } + else + { + $type = "NotExists" + } + + return $type +} + +# Converts CimInstance array of type KeyValuePair to hashtable +function Convert-KeyValuePairArrayToHashtable +{ + param ( + [parameter(Mandatory = $true)] + [Microsoft.Management.Infrastructure.CimInstance[]] + $array + ) + + $hashtable = @{} + foreach($item in $array) + { + $hashtable += @{$item.Key = $item.Value} + } + + return $hashtable +} + +# Gets cache for specific DestinationPath and Uri +function Get-Cache +{ + param ( + [parameter(Mandatory = $true)] + [ValidateNotNullOrEmpty()] + [System.String] + $DestinationPath, + + [parameter(Mandatory = $true)] + [ValidateNotNullOrEmpty()] + [System.String] + $Uri + ) + + $cacheContent = $null + $key = Get-CacheKey -DestinationPath $DestinationPath -Uri $Uri + $path = Join-Path $script:cacheLocation $key + + Write-Debug "Looking for path $path" + if(!(Test-Path $path)) + { + Write-Debug "No cache found for DestinationPath = $DestinationPath and Uri = $Uri. CacheKey = $key" + $cacheContent = $null + } + else + { + $cacheContent = Import-CliXml $path + Write-Debug "Found cache for DestinationPath = $DestinationPath and Uri = $Uri. CacheKey = $key" + } + + return $cacheContent +} + +# Creates or updates cache for specific DestinationPath and Uri +function Update-Cache +{ + param ( + [parameter(Mandatory = $true)] + [ValidateNotNullOrEmpty()] + [System.String] + $DestinationPath, + + [parameter(Mandatory = $true)] + [ValidateNotNullOrEmpty()] + [System.String] + $Uri, + + [parameter(Mandatory = $true)] + [Object] + $InputObject + ) + + $key = Get-CacheKey -DestinationPath $DestinationPath -Uri $Uri + $path = Join-Path $script:cacheLocation $key + + if(-not (Test-Path $script:cacheLocation)) + { + mkdir $script:cacheLocation | Out-Null + } + + Write-Debug "Updating cache for DestinationPath = $DestinationPath and Uri = $Uri. CacheKey = $key" + Export-CliXml -Path $path -InputObject $InputObject -Force +} + +# Returns cache key for given parameters +function Get-CacheKey +{ + param ( + [parameter(Mandatory = $true)] + [ValidateNotNullOrEmpty()] + [System.String] + $DestinationPath, + + [parameter(Mandatory = $true)] + [ValidateNotNullOrEmpty()] + [System.String] + $Uri + ) + $key = [string]::Join("", @($DestinationPath, $Uri)).GetHashCode().ToString() + return $key +} + +Export-ModuleMember -Function *-TargetResource + + + From b15caca1f6c7365dcf73c6791bb8be48148def4c Mon Sep 17 00:00:00 2001 From: Tiberriver256 Date: Mon, 7 Mar 2016 19:58:49 -0500 Subject: [PATCH 03/34] Revert "Added appropriate Write-Debug lines" This reverts commit 9896e2cf14eee8ae432ba563e75c07dab8c30443. --- .../MSFT_xRemoteFile/MSFT_xRemoteFile.psm1 | 953 +++++++++--------- 1 file changed, 476 insertions(+), 477 deletions(-) diff --git a/DSCResources/MSFT_xRemoteFile/MSFT_xRemoteFile.psm1 b/DSCResources/MSFT_xRemoteFile/MSFT_xRemoteFile.psm1 index b5dc8f738..b50e8c333 100644 --- a/DSCResources/MSFT_xRemoteFile/MSFT_xRemoteFile.psm1 +++ b/DSCResources/MSFT_xRemoteFile/MSFT_xRemoteFile.psm1 @@ -1,483 +1,482 @@ -data localizedData -{ - # culture="en-US" - ConvertFrom-StringData @' -InvalidWebUriError=Specified URI is not valid: "{0}". Only http and https paths are accepted. -InvalidDestinationPathSchemeError=Specified DestinationPath is not valid: "{0}". DestinationPath should be absolute path. -DestinationPathIsUncError=Specified DestinationPath is not valid: "{0}". DestinationPath should be local path instead of UNC path. -DestinationPathHasInvalidCharactersError=Specified DestinationPath is not valid: "{0}". DestinationPath should be contains following characters: * ? " < > | -DestinationPathEndsWithInvalidCharacterError=Specified DestinationPath is not valid: "{0}". DestinationPath should not end with / or \\ -'@ -} - -# Path where cache will be stored. It's cleared whenever LCM gets new configuration. -$script:cacheLocation = "$env:ProgramData\Microsoft\Windows\PowerShell\Configuration\BuiltinProvCache\MSFT_xRemoteFile" - -# The Get-TargetResource function is used to fetch the status of file specified in DestinationPath on the target machine. -function Get-TargetResource -{ - [CmdletBinding()] - [OutputType([System.Collections.Hashtable])] - param - ( - [parameter(Mandatory = $true)] - [ValidateNotNullOrEmpty()] - [System.String] - $DestinationPath, - - [parameter(Mandatory = $true)] - [ValidateNotNullOrEmpty()] - [System.String] - $Uri - ) - - # Check whether DestinationPath is existing file - $fileExists = $false - $pathItemType = Get-PathItemType -path $DestinationPath - switch($pathItemType) - { - "File" { - Write-Verbose "DestinationPath: '$DestinationPath' is existing file on the machine" - $fileExists = $true - } - - "Directory" { - Write-Verbose "DestinationPath: '$DestinationPath' is existing directory on the machine" - - # If it's existing directory, let's check whether expectedDestinationPath exists - $uriFileName = Split-Path $Uri -Leaf - $expectedDestinationPath = Join-Path $DestinationPath $uriFileName - if (Test-Path $expectedDestinationPath) { - Write-Verbose "File $uriFileName exists in DestinationPath" - $fileExists = $true - } - } - - "Other" { - Write-Verbose "DestinationPath: '$DestinationPath' has unknown type: '$pathItemType'" - } - - "NotExists" { - Write-Verbose "DestinationPath: '$DestinationPath' doesn't exist on the machine" - } - } - - $ensure = "Absent" - if ($fileExists) - { - $ensure = "Present" - } - - $returnValue = @{ - DestinationPath = $DestinationPath - Ensure = $ensure - } - - $returnValue -} - -# The Set-TargetResource function is used to download file found under Uri location to DestinationPath -# Additional parameters can be specified to configure web request -function Set-TargetResource -{ - [CmdletBinding()] - param - ( - [parameter(Mandatory = $true)] - [ValidateNotNullOrEmpty()] - [System.String] - $DestinationPath, - - [parameter(Mandatory = $true)] - [ValidateNotNullOrEmpty()] - [System.String] - $Uri, - - [System.String] - $UserAgent, - - [Microsoft.Management.Infrastructure.CimInstance[]] - $Headers, - - [System.Management.Automation.PSCredential] - $Credential, - +data localizedData +{ + # culture="en-US" + ConvertFrom-StringData @' +InvalidWebUriError=Specified URI is not valid: "{0}". Only http and https paths are accepted. +InvalidDestinationPathSchemeError=Specified DestinationPath is not valid: "{0}". DestinationPath should be absolute path. +DestinationPathIsUncError=Specified DestinationPath is not valid: "{0}". DestinationPath should be local path instead of UNC path. +DestinationPathHasInvalidCharactersError=Specified DestinationPath is not valid: "{0}". DestinationPath should be contains following characters: * ? " < > | +DestinationPathEndsWithInvalidCharacterError=Specified DestinationPath is not valid: "{0}". DestinationPath should not end with / or \\ +'@ +} + +# Path where cache will be stored. It's cleared whenever LCM gets new configuration. +$script:cacheLocation = "$env:ProgramData\Microsoft\Windows\PowerShell\Configuration\BuiltinProvCache\MSFT_xRemoteFile" + +# The Get-TargetResource function is used to fetch the status of file specified in DestinationPath on the target machine. +function Get-TargetResource +{ + [CmdletBinding()] + [OutputType([System.Collections.Hashtable])] + param + ( + [parameter(Mandatory = $true)] + [ValidateNotNullOrEmpty()] + [System.String] + $DestinationPath, + + [parameter(Mandatory = $true)] + [ValidateNotNullOrEmpty()] + [System.String] + $Uri + ) + + # Check whether DestinationPath is existing file + $fileExists = $false + $pathItemType = Get-PathItemType -path $DestinationPath + switch($pathItemType) + { + "File" { + Write-Verbose "DestinationPath: '$DestinationPath' is existing file on the machine" + $fileExists = $true + } + + "Directory" { + Write-Verbose "DestinationPath: '$DestinationPath' is existing directory on the machine" + + # If it's existing directory, let's check whether expectedDestinationPath exists + $uriFileName = Split-Path $Uri -Leaf + $expectedDestinationPath = Join-Path $DestinationPath $uriFileName + if (Test-Path $expectedDestinationPath) { + Write-Verbose "File $uriFileName exists in DestinationPath" + $fileExists = $true + } + } + + "Other" { + Write-Verbose "DestinationPath: '$DestinationPath' has unknown type: '$pathItemType'" + } + + "NotExists" { + Write-Verbose "DestinationPath: '$DestinationPath' doesn't exist on the machine" + } + } + + $ensure = "Absent" + if ($fileExists) + { + $ensure = "Present" + } + + $returnValue = @{ + DestinationPath = $DestinationPath + Ensure = $ensure + } + + $returnValue +} + +# The Set-TargetResource function is used to download file found under Uri location to DestinationPath +# Additional parameters can be specified to configure web request +function Set-TargetResource +{ + [CmdletBinding()] + param + ( + [parameter(Mandatory = $true)] + [ValidateNotNullOrEmpty()] + [System.String] + $DestinationPath, + + [parameter(Mandatory = $true)] + [ValidateNotNullOrEmpty()] + [System.String] + $Uri, + + [System.String] + $UserAgent, + + [Microsoft.Management.Infrastructure.CimInstance[]] + $Headers, + + [System.Management.Automation.PSCredential] + $Credential, + [parameter(Mandatory = $false)] [System.Boolean] - $MatchSource = $true - ) - - # Validate Uri - if (!(Check-UriScheme -uri $Uri -scheme "http") -and !(Check-UriScheme -uri $Uri -scheme "https")) - { - $errorId = "UriValidationFailure"; - $errorMessage = $($LocalizedData.InvalidWebUriError) -f ${Uri} - Throw-InvalidDataException -errorId $errorId -errorMessage $errorMessage - } - - # Validate DestinationPath scheme - if (!(Check-UriScheme -uri $DestinationPath -scheme "file")) - { - $errorMessage = $($LocalizedData.InvalidDestinationPathSchemeError) -f ${DestinationPath} - Throw-InvalidDataException -errorId "DestinationPathSchemeValidationFailure" -errorMessage $errorMessage - } - - # Validate DestinationPath is not UNC path - if ($DestinationPath.StartsWith("\\")) - { - $errorMessage = $($LocalizedData.DestinationPathIsUncError) -f ${DestinationPath} - Throw-InvalidDataException -errorId "DestinationPathIsUncFailure" -errorMessage $errorMessage - } - - # Validate DestinationPath does not contain invalid characters - $invalidCharacters = '*','?','"','<','>','|' - $invalidCharacters | % { - if ($DestinationPath.Contains($_) ){ - $errorMessage = $($LocalizedData.DestinationPathHasInvalidCharactersError) -f ${DestinationPath} - Throw-InvalidDataException -errorId "DestinationPathHasInvalidCharactersError" -errorMessage $errorMessage - } - } - - # Validate DestinationPath does not end with / or \ (Invoke-WebRequest requirement) - if ($DestinationPath.EndsWith('/') -or $DestinationPath.EndsWith('\')){ - $errorMessage = $($LocalizedData.DestinationPathEndsWithInvalidCharacterError) -f ${DestinationPath} - Throw-InvalidDataException -errorId "DestinationPathEndsWithInvalidCharacterError" -errorMessage $errorMessage - } - - # Check whether DestinationPath's parent directory exists. Create if it doesn't. - $destinationPathParent = Split-Path $DestinationPath -Parent - if (!(Test-Path $destinationPathParent)) - { - New-Item -Type Directory -Path $destinationPathParent -Force - } - - # Check whether DestinationPath's leaf is an existing folder - $uriFileName = Split-Path $Uri -Leaf - if (Test-Path $DestinationPath -PathType Container) - { - $DestinationPath = Join-Path $DestinationPath $uriFileName - } - - # Remove DestinationPath and MatchSource from parameters as they are not parameters of Invoke-WebRequest - $PSBoundParameters.Remove("DestinationPath") | Out-Null; - $PSBoundParameters.Remove("MatchSource") | Out-Null; - - # Convert headers to hashtable - $PSBoundParameters.Remove("Headers") | Out-Null; - $headersHashtable = $null - - if ($Headers -ne $null) - { - $headersHashtable = Convert-KeyValuePairArrayToHashtable -array $Headers - } - - # Invoke web request - try - { - Write-Verbose "Downloading $Uri to $DestinationPath" - Invoke-WebRequest @PSBoundParameters -Headers $headersHashtable -outFile $DestinationPath - } - catch [System.OutOfMemoryException] - { - throw "Received OutOfMemoryException. Possible cause is the requested file being too big. $_" - } - catch [System.Exception] - { - throw "Invoking web request failed with error $($_.Exception.Response.StatusCode.Value__): $($_.Exception.Response.StatusDescription)" - } - - # Update cache - if (Test-Path $DestinationPath) - { - $downloadedFile = Get-Item $DestinationPath - $lastWriteTime = $downloadedFile.LastWriteTimeUtc - $inputObject = @{} - $inputObject["LastWriteTime"] = $lastWriteTime - Update-Cache -DestinationPath $DestinationPath -Uri $Uri -InputObject $inputObject - } -} - -# The Test-TargetResource function is used to validate if the DestinationPath exists on the machine. -function Test-TargetResource -{ - [CmdletBinding()] - [OutputType([System.Boolean])] - param - ( - [parameter(Mandatory = $true)] - [ValidateNotNullOrEmpty()] - [System.String] - $DestinationPath, - - [parameter(Mandatory = $true)] - [ValidateNotNullOrEmpty()] - [System.String] - $Uri, - - [System.String] - $UserAgent, - - [Microsoft.Management.Infrastructure.CimInstance[]] - $Headers, - - [System.Management.Automation.PSCredential] - $Credential, - + $MatchSource = $true + ) + + # Validate Uri + if (!(Check-UriScheme -uri $Uri -scheme "http") -and !(Check-UriScheme -uri $Uri -scheme "https")) + { + $errorId = "UriValidationFailure"; + $errorMessage = $($LocalizedData.InvalidWebUriError) -f ${Uri} + Throw-InvalidDataException -errorId $errorId -errorMessage $errorMessage + } + + # Validate DestinationPath scheme + if (!(Check-UriScheme -uri $DestinationPath -scheme "file")) + { + $errorMessage = $($LocalizedData.InvalidDestinationPathSchemeError) -f ${DestinationPath} + Throw-InvalidDataException -errorId "DestinationPathSchemeValidationFailure" -errorMessage $errorMessage + } + + # Validate DestinationPath is not UNC path + if ($DestinationPath.StartsWith("\\")) + { + $errorMessage = $($LocalizedData.DestinationPathIsUncError) -f ${DestinationPath} + Throw-InvalidDataException -errorId "DestinationPathIsUncFailure" -errorMessage $errorMessage + } + + # Validate DestinationPath does not contain invalid characters + $invalidCharacters = '*','?','"','<','>','|' + $invalidCharacters | % { + if ($DestinationPath.Contains($_) ){ + $errorMessage = $($LocalizedData.DestinationPathHasInvalidCharactersError) -f ${DestinationPath} + Throw-InvalidDataException -errorId "DestinationPathHasInvalidCharactersError" -errorMessage $errorMessage + } + } + + # Validate DestinationPath does not end with / or \ (Invoke-WebRequest requirement) + if ($DestinationPath.EndsWith('/') -or $DestinationPath.EndsWith('\')){ + $errorMessage = $($LocalizedData.DestinationPathEndsWithInvalidCharacterError) -f ${DestinationPath} + Throw-InvalidDataException -errorId "DestinationPathEndsWithInvalidCharacterError" -errorMessage $errorMessage + } + + # Check whether DestinationPath's parent directory exists. Create if it doesn't. + $destinationPathParent = Split-Path $DestinationPath -Parent + if (!(Test-Path $destinationPathParent)) + { + New-Item -Type Directory -Path $destinationPathParent -Force + } + + # Check whether DestinationPath's leaf is an existing folder + $uriFileName = Split-Path $Uri -Leaf + if (Test-Path $DestinationPath -PathType Container) + { + $DestinationPath = Join-Path $DestinationPath $uriFileName + } + + # Remove DestinationPath and MatchSource from parameters as they are not parameters of Invoke-WebRequest + $PSBoundParameters.Remove("DestinationPath") | Out-Null; + $PSBoundParameters.Remove("MatchSource") | Out-Null; + + # Convert headers to hashtable + $PSBoundParameters.Remove("Headers") | Out-Null; + $headersHashtable = $null + + if ($Headers -ne $null) + { + $headersHashtable = Convert-KeyValuePairArrayToHashtable -array $Headers + } + + # Invoke web request + try + { + Write-Verbose "Downloading $Uri to $DestinationPath" + Invoke-WebRequest @PSBoundParameters -Headers $headersHashtable -outFile $DestinationPath + } + catch [System.OutOfMemoryException] + { + throw "Received OutOfMemoryException. Possible cause is the requested file being too big. $_" + } + catch [System.Exception] + { + throw "Invoking web request failed with error $($_.Exception.Response.StatusCode.Value__): $($_.Exception.Response.StatusDescription)" + } + + # Update cache + if (Test-Path $DestinationPath) + { + $downloadedFile = Get-Item $DestinationPath + $lastWriteTime = $downloadedFile.LastWriteTimeUtc + $inputObject = @{} + $inputObject["LastWriteTime"] = $lastWriteTime + Update-Cache -DestinationPath $DestinationPath -Uri $Uri -InputObject $inputObject + } +} + +# The Test-TargetResource function is used to validate if the DestinationPath exists on the machine. +function Test-TargetResource +{ + [CmdletBinding()] + [OutputType([System.Boolean])] + param + ( + [parameter(Mandatory = $true)] + [ValidateNotNullOrEmpty()] + [System.String] + $DestinationPath, + + [parameter(Mandatory = $true)] + [ValidateNotNullOrEmpty()] + [System.String] + $Uri, + + [System.String] + $UserAgent, + + [Microsoft.Management.Infrastructure.CimInstance[]] + $Headers, + + [System.Management.Automation.PSCredential] + $Credential, + [parameter(Mandatory = $false)] [System.Boolean] - $MatchSource = $true - ) - - # Check whether DestinationPath points to existing file or directory - $fileExists = $false - $uriFileName = Split-Path $Uri -Leaf - $pathItemType = Get-PathItemType -path $DestinationPath - switch($pathItemType) - { - "File" { - Write-Debug "DestinationPath: '$DestinationPath' is existing file on the machine" - - if ($MatchSource) { - $file = Get-Item $DestinationPath - # Getting cache. It's cleared every time user runs Start-DscConfiguration - $cache = Get-Cache -DestinationPath $DestinationPath -Uri $Uri - - if ($cache -ne $null -and ($cache.LastWriteTime -eq $file.LastWriteTimeUtc)) - { - Write-Debug "Cache reflects current state. No need for downloading file." - $fileExists = $true - } - else - { - Write-Debug "Cache is empty or it doesn't reflect current state. File will be downloaded." - } - } else { - Write-Debug "Destination file size is not the same as source file. File will be downloaded." + $MatchSource = $true + ) + + # Check whether DestinationPath points to existing file or directory + $fileExists = $false + $uriFileName = Split-Path $Uri -Leaf + $pathItemType = Get-PathItemType -path $DestinationPath + switch($pathItemType) + { + "File" { + Write-Debug "DestinationPath: '$DestinationPath' is existing file on the machine" + + if ($MatchSource) { + $file = Get-Item $DestinationPath + # Getting cache. It's cleared every time user runs Start-DscConfiguration + $cache = Get-Cache -DestinationPath $DestinationPath -Uri $Uri + + if ($cache -ne $null -and ($cache.LastWriteTime -eq $file.LastWriteTimeUtc)) + { + Write-Debug "Cache reflects current state. No need for downloading file." + $fileExists = $true + } + else + { + Write-Debug "Cache is empty or it doesn't reflect current state. File will be downloaded." + } + } else { + Write-Debug "MatchSource is false. No need for downloading file." [System.Net.WebClient]$wc = [System.Net.WebClient]::New() $wc.OpenRead($URI) - [Long]$bytes_total = $wc.ResponseHeaders["Content-Length"] - if($bytes_total -eq (Get-Item $DestinationPath).Length) - { - Write-Debug "MatchSource is false. No need for downloading file." - $fileExists = $true - } - } - } - - "Directory" { - Write-Debug "DestinationPath: '$DestinationPath' is existing directory on the machine" - $expectedDestinationPath = Join-Path $DestinationPath $uriFileName - - if (Test-Path $expectedDestinationPath) { - if ($MatchSource) { - $file = Get-Item $expectedDestinationPath - $cache = Get-Cache -DestinationPath $expectedDestinationPath -Uri $Uri - if ($cache -ne $null -and ($cache.LastWriteTime -eq $file.LastWriteTimeUtc)) - { - Write-Debug "Cache reflects current state. No need for downloading file." - $fileExists = $true - } - else - { - Write-Debug "Cache is empty or it doesn't reflect current state. File will be downloaded." - } - } else { - Write-Debug "MatchSource is false. No need for downloading file." - $fileExists = $true - } - } - } - - "Other" { - Write-Debug "DestinationPath: '$DestinationPath' has unknown type: '$pathItemType'" - } - - "NotExists" { - Write-Debug "DestinationPath: '$DestinationPath' doesn't exist on the machine" - } - } - - $result = $fileExists - - $result -} - -# Throws terminating error of category InvalidData with specified errorId and errorMessage -function Throw-InvalidDataException -{ - param( - [parameter(Mandatory = $true)] - [System.String] - $errorId, - [parameter(Mandatory = $true)] - [System.String] - $errorMessage - ) - - $errorCategory = [System.Management.Automation.ErrorCategory]::InvalidData - $exception = New-Object System.InvalidOperationException $errorMessage - $errorRecord = New-Object System.Management.Automation.ErrorRecord $exception, $errorId, $errorCategory, $null - throw $errorRecord -} - -# Checks whether given URI represents specific scheme -# Most common schemes: file, http, https, ftp -# We can also specify logical expressions like: [http|https] -function Check-UriScheme -{ - param ( - [parameter(Mandatory = $true)] - [System.String] - $uri, - [parameter(Mandatory = $true)] - [System.String] - $scheme - ) - $newUri = $uri -as [System.URI] - $newUri.AbsoluteURI -ne $null -and $newUri.Scheme -match $scheme -} - -# Gets type of the item which path points to. -# Returns: File, Directory, Other or NotExists -function Get-PathItemType -{ - param ( - [parameter(Mandatory = $true)] - [System.String] - $path - ) - - $type = $null - - # Check whether path exists - if (Test-Path $path) - { - # Check type of the path - $pathItem = Get-Item $path - $pathItemType = $pathItem.GetType().Name - if ($pathItemType -eq "FileInfo") - { - $type = "File" - } - elseif ($pathItemType -eq "DirectoryInfo") - { - $type = "Directory" - } - else - { - $type = "Other" - } - } - else - { - $type = "NotExists" - } - - return $type -} - -# Converts CimInstance array of type KeyValuePair to hashtable -function Convert-KeyValuePairArrayToHashtable -{ - param ( - [parameter(Mandatory = $true)] - [Microsoft.Management.Infrastructure.CimInstance[]] - $array - ) - - $hashtable = @{} - foreach($item in $array) - { - $hashtable += @{$item.Key = $item.Value} - } - - return $hashtable -} - -# Gets cache for specific DestinationPath and Uri -function Get-Cache -{ - param ( - [parameter(Mandatory = $true)] - [ValidateNotNullOrEmpty()] - [System.String] - $DestinationPath, - - [parameter(Mandatory = $true)] - [ValidateNotNullOrEmpty()] - [System.String] - $Uri - ) - - $cacheContent = $null - $key = Get-CacheKey -DestinationPath $DestinationPath -Uri $Uri - $path = Join-Path $script:cacheLocation $key - - Write-Debug "Looking for path $path" - if(!(Test-Path $path)) - { - Write-Debug "No cache found for DestinationPath = $DestinationPath and Uri = $Uri. CacheKey = $key" - $cacheContent = $null - } - else - { - $cacheContent = Import-CliXml $path - Write-Debug "Found cache for DestinationPath = $DestinationPath and Uri = $Uri. CacheKey = $key" - } - - return $cacheContent -} - -# Creates or updates cache for specific DestinationPath and Uri -function Update-Cache -{ - param ( - [parameter(Mandatory = $true)] - [ValidateNotNullOrEmpty()] - [System.String] - $DestinationPath, - - [parameter(Mandatory = $true)] - [ValidateNotNullOrEmpty()] - [System.String] - $Uri, - - [parameter(Mandatory = $true)] - [Object] - $InputObject - ) - - $key = Get-CacheKey -DestinationPath $DestinationPath -Uri $Uri - $path = Join-Path $script:cacheLocation $key - - if(-not (Test-Path $script:cacheLocation)) - { - mkdir $script:cacheLocation | Out-Null - } - - Write-Debug "Updating cache for DestinationPath = $DestinationPath and Uri = $Uri. CacheKey = $key" - Export-CliXml -Path $path -InputObject $InputObject -Force -} - -# Returns cache key for given parameters -function Get-CacheKey -{ - param ( - [parameter(Mandatory = $true)] - [ValidateNotNullOrEmpty()] - [System.String] - $DestinationPath, - - [parameter(Mandatory = $true)] - [ValidateNotNullOrEmpty()] - [System.String] - $Uri - ) - $key = [string]::Join("", @($DestinationPath, $Uri)).GetHashCode().ToString() - return $key -} - -Export-ModuleMember -Function *-TargetResource - - - + [Long]$bytes_total = $wc.ResponseHeaders["Content-Length"] + if($bytes_total -eq (Get-Item $DestinationPath).Length) + { + $fileExists = $true + } + } + } + + "Directory" { + Write-Debug "DestinationPath: '$DestinationPath' is existing directory on the machine" + $expectedDestinationPath = Join-Path $DestinationPath $uriFileName + + if (Test-Path $expectedDestinationPath) { + if ($MatchSource) { + $file = Get-Item $expectedDestinationPath + $cache = Get-Cache -DestinationPath $expectedDestinationPath -Uri $Uri + if ($cache -ne $null -and ($cache.LastWriteTime -eq $file.LastWriteTimeUtc)) + { + Write-Debug "Cache reflects current state. No need for downloading file." + $fileExists = $true + } + else + { + Write-Debug "Cache is empty or it doesn't reflect current state. File will be downloaded." + } + } else { + Write-Debug "MatchSource is false. No need for downloading file." + $fileExists = $true + } + } + } + + "Other" { + Write-Debug "DestinationPath: '$DestinationPath' has unknown type: '$pathItemType'" + } + + "NotExists" { + Write-Debug "DestinationPath: '$DestinationPath' doesn't exist on the machine" + } + } + + $result = $fileExists + + $result +} + +# Throws terminating error of category InvalidData with specified errorId and errorMessage +function Throw-InvalidDataException +{ + param( + [parameter(Mandatory = $true)] + [System.String] + $errorId, + [parameter(Mandatory = $true)] + [System.String] + $errorMessage + ) + + $errorCategory = [System.Management.Automation.ErrorCategory]::InvalidData + $exception = New-Object System.InvalidOperationException $errorMessage + $errorRecord = New-Object System.Management.Automation.ErrorRecord $exception, $errorId, $errorCategory, $null + throw $errorRecord +} + +# Checks whether given URI represents specific scheme +# Most common schemes: file, http, https, ftp +# We can also specify logical expressions like: [http|https] +function Check-UriScheme +{ + param ( + [parameter(Mandatory = $true)] + [System.String] + $uri, + [parameter(Mandatory = $true)] + [System.String] + $scheme + ) + $newUri = $uri -as [System.URI] + $newUri.AbsoluteURI -ne $null -and $newUri.Scheme -match $scheme +} + +# Gets type of the item which path points to. +# Returns: File, Directory, Other or NotExists +function Get-PathItemType +{ + param ( + [parameter(Mandatory = $true)] + [System.String] + $path + ) + + $type = $null + + # Check whether path exists + if (Test-Path $path) + { + # Check type of the path + $pathItem = Get-Item $path + $pathItemType = $pathItem.GetType().Name + if ($pathItemType -eq "FileInfo") + { + $type = "File" + } + elseif ($pathItemType -eq "DirectoryInfo") + { + $type = "Directory" + } + else + { + $type = "Other" + } + } + else + { + $type = "NotExists" + } + + return $type +} + +# Converts CimInstance array of type KeyValuePair to hashtable +function Convert-KeyValuePairArrayToHashtable +{ + param ( + [parameter(Mandatory = $true)] + [Microsoft.Management.Infrastructure.CimInstance[]] + $array + ) + + $hashtable = @{} + foreach($item in $array) + { + $hashtable += @{$item.Key = $item.Value} + } + + return $hashtable +} + +# Gets cache for specific DestinationPath and Uri +function Get-Cache +{ + param ( + [parameter(Mandatory = $true)] + [ValidateNotNullOrEmpty()] + [System.String] + $DestinationPath, + + [parameter(Mandatory = $true)] + [ValidateNotNullOrEmpty()] + [System.String] + $Uri + ) + + $cacheContent = $null + $key = Get-CacheKey -DestinationPath $DestinationPath -Uri $Uri + $path = Join-Path $script:cacheLocation $key + + Write-Debug "Looking for path $path" + if(!(Test-Path $path)) + { + Write-Debug "No cache found for DestinationPath = $DestinationPath and Uri = $Uri. CacheKey = $key" + $cacheContent = $null + } + else + { + $cacheContent = Import-CliXml $path + Write-Debug "Found cache for DestinationPath = $DestinationPath and Uri = $Uri. CacheKey = $key" + } + + return $cacheContent +} + +# Creates or updates cache for specific DestinationPath and Uri +function Update-Cache +{ + param ( + [parameter(Mandatory = $true)] + [ValidateNotNullOrEmpty()] + [System.String] + $DestinationPath, + + [parameter(Mandatory = $true)] + [ValidateNotNullOrEmpty()] + [System.String] + $Uri, + + [parameter(Mandatory = $true)] + [Object] + $InputObject + ) + + $key = Get-CacheKey -DestinationPath $DestinationPath -Uri $Uri + $path = Join-Path $script:cacheLocation $key + + if(-not (Test-Path $script:cacheLocation)) + { + mkdir $script:cacheLocation | Out-Null + } + + Write-Debug "Updating cache for DestinationPath = $DestinationPath and Uri = $Uri. CacheKey = $key" + Export-CliXml -Path $path -InputObject $InputObject -Force +} + +# Returns cache key for given parameters +function Get-CacheKey +{ + param ( + [parameter(Mandatory = $true)] + [ValidateNotNullOrEmpty()] + [System.String] + $DestinationPath, + + [parameter(Mandatory = $true)] + [ValidateNotNullOrEmpty()] + [System.String] + $Uri + ) + $key = [string]::Join("", @($DestinationPath, $Uri)).GetHashCode().ToString() + return $key +} + +Export-ModuleMember -Function *-TargetResource + + + From c6d5f0ee3cc6c699657891bf7056fb9dab40d0e5 Mon Sep 17 00:00:00 2001 From: Tiberriver256 Date: Mon, 7 Mar 2016 20:00:24 -0500 Subject: [PATCH 04/34] Added appropriate Write-Debug lines --- DSCResources/MSFT_xRemoteFile/MSFT_xRemoteFile.psm1 | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/DSCResources/MSFT_xRemoteFile/MSFT_xRemoteFile.psm1 b/DSCResources/MSFT_xRemoteFile/MSFT_xRemoteFile.psm1 index b50e8c333..fb101efdc 100644 --- a/DSCResources/MSFT_xRemoteFile/MSFT_xRemoteFile.psm1 +++ b/DSCResources/MSFT_xRemoteFile/MSFT_xRemoteFile.psm1 @@ -252,13 +252,14 @@ function Test-TargetResource Write-Debug "Cache is empty or it doesn't reflect current state. File will be downloaded." } } else { - Write-Debug "MatchSource is false. No need for downloading file." + Write-Debug "Destination file size is not the same as source file. File will be downloaded." [System.Net.WebClient]$wc = [System.Net.WebClient]::New() $wc.OpenRead($URI) - [Long]$bytes_total = $wc.ResponseHeaders["Content-Length"] - if($bytes_total -eq (Get-Item $DestinationPath).Length) - { - $fileExists = $true + [Long]$bytes_total = $wc.ResponseHeaders["Content-Length"] + if($bytes_total -eq (Get-Item $DestinationPath).Length) + { + Write-Debug "MatchSource is false. No need for downloading file." + $fileExists = $true } } } From ca2c8d4cdd4ff3573e66ba409a2735146dc86fbc Mon Sep 17 00:00:00 2001 From: Micah Rairdon Date: Mon, 7 Mar 2016 20:29:10 -0500 Subject: [PATCH 05/34] Corrected Write-Debug placement and added clarification --- DSCResources/MSFT_xRemoteFile/MSFT_xRemoteFile.psm1 | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/DSCResources/MSFT_xRemoteFile/MSFT_xRemoteFile.psm1 b/DSCResources/MSFT_xRemoteFile/MSFT_xRemoteFile.psm1 index fb101efdc..444667aa1 100644 --- a/DSCResources/MSFT_xRemoteFile/MSFT_xRemoteFile.psm1 +++ b/DSCResources/MSFT_xRemoteFile/MSFT_xRemoteFile.psm1 @@ -251,16 +251,19 @@ function Test-TargetResource { Write-Debug "Cache is empty or it doesn't reflect current state. File will be downloaded." } - } else { - Write-Debug "Destination file size is not the same as source file. File will be downloaded." + } else { [System.Net.WebClient]$wc = [System.Net.WebClient]::New() $wc.OpenRead($URI) [Long]$bytes_total = $wc.ResponseHeaders["Content-Length"] if($bytes_total -eq (Get-Item $DestinationPath).Length) { - Write-Debug "MatchSource is false. No need for downloading file." + Write-Debug "Destination and source file are the same size. No need for downloading file." $fileExists = $true } + else + { + Write-Debug "Destination file size is not the same as source file. File will be downloaded." + } } } From f45d4a0c99deed84ead450be73e0c7fb9c34b539 Mon Sep 17 00:00:00 2001 From: Tiberriver256 Date: Mon, 7 Mar 2016 20:51:54 -0500 Subject: [PATCH 06/34] Revert "Corrected Write-Debug placement and added clarification" This reverts commit ca2c8d4cdd4ff3573e66ba409a2735146dc86fbc. --- DSCResources/MSFT_xRemoteFile/MSFT_xRemoteFile.psm1 | 9 +++------ 1 file changed, 3 insertions(+), 6 deletions(-) diff --git a/DSCResources/MSFT_xRemoteFile/MSFT_xRemoteFile.psm1 b/DSCResources/MSFT_xRemoteFile/MSFT_xRemoteFile.psm1 index 444667aa1..fb101efdc 100644 --- a/DSCResources/MSFT_xRemoteFile/MSFT_xRemoteFile.psm1 +++ b/DSCResources/MSFT_xRemoteFile/MSFT_xRemoteFile.psm1 @@ -251,19 +251,16 @@ function Test-TargetResource { Write-Debug "Cache is empty or it doesn't reflect current state. File will be downloaded." } - } else { + } else { + Write-Debug "Destination file size is not the same as source file. File will be downloaded." [System.Net.WebClient]$wc = [System.Net.WebClient]::New() $wc.OpenRead($URI) [Long]$bytes_total = $wc.ResponseHeaders["Content-Length"] if($bytes_total -eq (Get-Item $DestinationPath).Length) { - Write-Debug "Destination and source file are the same size. No need for downloading file." + Write-Debug "MatchSource is false. No need for downloading file." $fileExists = $true } - else - { - Write-Debug "Destination file size is not the same as source file. File will be downloaded." - } } } From a9e43d5246771267b8e5d4d757cf4f825893a7d1 Mon Sep 17 00:00:00 2001 From: Tiberriver256 Date: Mon, 7 Mar 2016 20:51:57 -0500 Subject: [PATCH 07/34] Revert "Added appropriate Write-Debug lines" This reverts commit c6d5f0ee3cc6c699657891bf7056fb9dab40d0e5. --- DSCResources/MSFT_xRemoteFile/MSFT_xRemoteFile.psm1 | 11 +++++------ 1 file changed, 5 insertions(+), 6 deletions(-) diff --git a/DSCResources/MSFT_xRemoteFile/MSFT_xRemoteFile.psm1 b/DSCResources/MSFT_xRemoteFile/MSFT_xRemoteFile.psm1 index fb101efdc..b50e8c333 100644 --- a/DSCResources/MSFT_xRemoteFile/MSFT_xRemoteFile.psm1 +++ b/DSCResources/MSFT_xRemoteFile/MSFT_xRemoteFile.psm1 @@ -252,14 +252,13 @@ function Test-TargetResource Write-Debug "Cache is empty or it doesn't reflect current state. File will be downloaded." } } else { - Write-Debug "Destination file size is not the same as source file. File will be downloaded." + Write-Debug "MatchSource is false. No need for downloading file." [System.Net.WebClient]$wc = [System.Net.WebClient]::New() $wc.OpenRead($URI) - [Long]$bytes_total = $wc.ResponseHeaders["Content-Length"] - if($bytes_total -eq (Get-Item $DestinationPath).Length) - { - Write-Debug "MatchSource is false. No need for downloading file." - $fileExists = $true + [Long]$bytes_total = $wc.ResponseHeaders["Content-Length"] + if($bytes_total -eq (Get-Item $DestinationPath).Length) + { + $fileExists = $true } } } From a2867fae0fca78be2ddb1b18e0f5d96ea35a3360 Mon Sep 17 00:00:00 2001 From: Tiberriver256 Date: Mon, 7 Mar 2016 20:52:00 -0500 Subject: [PATCH 08/34] Revert "Revert "Added appropriate Write-Debug lines"" This reverts commit b15caca1f6c7365dcf73c6791bb8be48148def4c. --- .../MSFT_xRemoteFile/MSFT_xRemoteFile.psm1 | 953 +++++++++--------- 1 file changed, 477 insertions(+), 476 deletions(-) diff --git a/DSCResources/MSFT_xRemoteFile/MSFT_xRemoteFile.psm1 b/DSCResources/MSFT_xRemoteFile/MSFT_xRemoteFile.psm1 index b50e8c333..b5dc8f738 100644 --- a/DSCResources/MSFT_xRemoteFile/MSFT_xRemoteFile.psm1 +++ b/DSCResources/MSFT_xRemoteFile/MSFT_xRemoteFile.psm1 @@ -1,482 +1,483 @@ -data localizedData -{ - # culture="en-US" - ConvertFrom-StringData @' -InvalidWebUriError=Specified URI is not valid: "{0}". Only http and https paths are accepted. -InvalidDestinationPathSchemeError=Specified DestinationPath is not valid: "{0}". DestinationPath should be absolute path. -DestinationPathIsUncError=Specified DestinationPath is not valid: "{0}". DestinationPath should be local path instead of UNC path. -DestinationPathHasInvalidCharactersError=Specified DestinationPath is not valid: "{0}". DestinationPath should be contains following characters: * ? " < > | -DestinationPathEndsWithInvalidCharacterError=Specified DestinationPath is not valid: "{0}". DestinationPath should not end with / or \\ -'@ -} - -# Path where cache will be stored. It's cleared whenever LCM gets new configuration. -$script:cacheLocation = "$env:ProgramData\Microsoft\Windows\PowerShell\Configuration\BuiltinProvCache\MSFT_xRemoteFile" - -# The Get-TargetResource function is used to fetch the status of file specified in DestinationPath on the target machine. -function Get-TargetResource -{ - [CmdletBinding()] - [OutputType([System.Collections.Hashtable])] - param - ( - [parameter(Mandatory = $true)] - [ValidateNotNullOrEmpty()] - [System.String] - $DestinationPath, - - [parameter(Mandatory = $true)] - [ValidateNotNullOrEmpty()] - [System.String] - $Uri - ) - - # Check whether DestinationPath is existing file - $fileExists = $false - $pathItemType = Get-PathItemType -path $DestinationPath - switch($pathItemType) - { - "File" { - Write-Verbose "DestinationPath: '$DestinationPath' is existing file on the machine" - $fileExists = $true - } - - "Directory" { - Write-Verbose "DestinationPath: '$DestinationPath' is existing directory on the machine" - - # If it's existing directory, let's check whether expectedDestinationPath exists - $uriFileName = Split-Path $Uri -Leaf - $expectedDestinationPath = Join-Path $DestinationPath $uriFileName - if (Test-Path $expectedDestinationPath) { - Write-Verbose "File $uriFileName exists in DestinationPath" - $fileExists = $true - } - } - - "Other" { - Write-Verbose "DestinationPath: '$DestinationPath' has unknown type: '$pathItemType'" - } - - "NotExists" { - Write-Verbose "DestinationPath: '$DestinationPath' doesn't exist on the machine" - } - } - - $ensure = "Absent" - if ($fileExists) - { - $ensure = "Present" - } - - $returnValue = @{ - DestinationPath = $DestinationPath - Ensure = $ensure - } - - $returnValue -} - -# The Set-TargetResource function is used to download file found under Uri location to DestinationPath -# Additional parameters can be specified to configure web request -function Set-TargetResource -{ - [CmdletBinding()] - param - ( - [parameter(Mandatory = $true)] - [ValidateNotNullOrEmpty()] - [System.String] - $DestinationPath, - - [parameter(Mandatory = $true)] - [ValidateNotNullOrEmpty()] - [System.String] - $Uri, - - [System.String] - $UserAgent, - - [Microsoft.Management.Infrastructure.CimInstance[]] - $Headers, - - [System.Management.Automation.PSCredential] - $Credential, - +data localizedData +{ + # culture="en-US" + ConvertFrom-StringData @' +InvalidWebUriError=Specified URI is not valid: "{0}". Only http and https paths are accepted. +InvalidDestinationPathSchemeError=Specified DestinationPath is not valid: "{0}". DestinationPath should be absolute path. +DestinationPathIsUncError=Specified DestinationPath is not valid: "{0}". DestinationPath should be local path instead of UNC path. +DestinationPathHasInvalidCharactersError=Specified DestinationPath is not valid: "{0}". DestinationPath should be contains following characters: * ? " < > | +DestinationPathEndsWithInvalidCharacterError=Specified DestinationPath is not valid: "{0}". DestinationPath should not end with / or \\ +'@ +} + +# Path where cache will be stored. It's cleared whenever LCM gets new configuration. +$script:cacheLocation = "$env:ProgramData\Microsoft\Windows\PowerShell\Configuration\BuiltinProvCache\MSFT_xRemoteFile" + +# The Get-TargetResource function is used to fetch the status of file specified in DestinationPath on the target machine. +function Get-TargetResource +{ + [CmdletBinding()] + [OutputType([System.Collections.Hashtable])] + param + ( + [parameter(Mandatory = $true)] + [ValidateNotNullOrEmpty()] + [System.String] + $DestinationPath, + + [parameter(Mandatory = $true)] + [ValidateNotNullOrEmpty()] + [System.String] + $Uri + ) + + # Check whether DestinationPath is existing file + $fileExists = $false + $pathItemType = Get-PathItemType -path $DestinationPath + switch($pathItemType) + { + "File" { + Write-Verbose "DestinationPath: '$DestinationPath' is existing file on the machine" + $fileExists = $true + } + + "Directory" { + Write-Verbose "DestinationPath: '$DestinationPath' is existing directory on the machine" + + # If it's existing directory, let's check whether expectedDestinationPath exists + $uriFileName = Split-Path $Uri -Leaf + $expectedDestinationPath = Join-Path $DestinationPath $uriFileName + if (Test-Path $expectedDestinationPath) { + Write-Verbose "File $uriFileName exists in DestinationPath" + $fileExists = $true + } + } + + "Other" { + Write-Verbose "DestinationPath: '$DestinationPath' has unknown type: '$pathItemType'" + } + + "NotExists" { + Write-Verbose "DestinationPath: '$DestinationPath' doesn't exist on the machine" + } + } + + $ensure = "Absent" + if ($fileExists) + { + $ensure = "Present" + } + + $returnValue = @{ + DestinationPath = $DestinationPath + Ensure = $ensure + } + + $returnValue +} + +# The Set-TargetResource function is used to download file found under Uri location to DestinationPath +# Additional parameters can be specified to configure web request +function Set-TargetResource +{ + [CmdletBinding()] + param + ( + [parameter(Mandatory = $true)] + [ValidateNotNullOrEmpty()] + [System.String] + $DestinationPath, + + [parameter(Mandatory = $true)] + [ValidateNotNullOrEmpty()] + [System.String] + $Uri, + + [System.String] + $UserAgent, + + [Microsoft.Management.Infrastructure.CimInstance[]] + $Headers, + + [System.Management.Automation.PSCredential] + $Credential, + [parameter(Mandatory = $false)] [System.Boolean] - $MatchSource = $true - ) - - # Validate Uri - if (!(Check-UriScheme -uri $Uri -scheme "http") -and !(Check-UriScheme -uri $Uri -scheme "https")) - { - $errorId = "UriValidationFailure"; - $errorMessage = $($LocalizedData.InvalidWebUriError) -f ${Uri} - Throw-InvalidDataException -errorId $errorId -errorMessage $errorMessage - } - - # Validate DestinationPath scheme - if (!(Check-UriScheme -uri $DestinationPath -scheme "file")) - { - $errorMessage = $($LocalizedData.InvalidDestinationPathSchemeError) -f ${DestinationPath} - Throw-InvalidDataException -errorId "DestinationPathSchemeValidationFailure" -errorMessage $errorMessage - } - - # Validate DestinationPath is not UNC path - if ($DestinationPath.StartsWith("\\")) - { - $errorMessage = $($LocalizedData.DestinationPathIsUncError) -f ${DestinationPath} - Throw-InvalidDataException -errorId "DestinationPathIsUncFailure" -errorMessage $errorMessage - } - - # Validate DestinationPath does not contain invalid characters - $invalidCharacters = '*','?','"','<','>','|' - $invalidCharacters | % { - if ($DestinationPath.Contains($_) ){ - $errorMessage = $($LocalizedData.DestinationPathHasInvalidCharactersError) -f ${DestinationPath} - Throw-InvalidDataException -errorId "DestinationPathHasInvalidCharactersError" -errorMessage $errorMessage - } - } - - # Validate DestinationPath does not end with / or \ (Invoke-WebRequest requirement) - if ($DestinationPath.EndsWith('/') -or $DestinationPath.EndsWith('\')){ - $errorMessage = $($LocalizedData.DestinationPathEndsWithInvalidCharacterError) -f ${DestinationPath} - Throw-InvalidDataException -errorId "DestinationPathEndsWithInvalidCharacterError" -errorMessage $errorMessage - } - - # Check whether DestinationPath's parent directory exists. Create if it doesn't. - $destinationPathParent = Split-Path $DestinationPath -Parent - if (!(Test-Path $destinationPathParent)) - { - New-Item -Type Directory -Path $destinationPathParent -Force - } - - # Check whether DestinationPath's leaf is an existing folder - $uriFileName = Split-Path $Uri -Leaf - if (Test-Path $DestinationPath -PathType Container) - { - $DestinationPath = Join-Path $DestinationPath $uriFileName - } - - # Remove DestinationPath and MatchSource from parameters as they are not parameters of Invoke-WebRequest - $PSBoundParameters.Remove("DestinationPath") | Out-Null; - $PSBoundParameters.Remove("MatchSource") | Out-Null; - - # Convert headers to hashtable - $PSBoundParameters.Remove("Headers") | Out-Null; - $headersHashtable = $null - - if ($Headers -ne $null) - { - $headersHashtable = Convert-KeyValuePairArrayToHashtable -array $Headers - } - - # Invoke web request - try - { - Write-Verbose "Downloading $Uri to $DestinationPath" - Invoke-WebRequest @PSBoundParameters -Headers $headersHashtable -outFile $DestinationPath - } - catch [System.OutOfMemoryException] - { - throw "Received OutOfMemoryException. Possible cause is the requested file being too big. $_" - } - catch [System.Exception] - { - throw "Invoking web request failed with error $($_.Exception.Response.StatusCode.Value__): $($_.Exception.Response.StatusDescription)" - } - - # Update cache - if (Test-Path $DestinationPath) - { - $downloadedFile = Get-Item $DestinationPath - $lastWriteTime = $downloadedFile.LastWriteTimeUtc - $inputObject = @{} - $inputObject["LastWriteTime"] = $lastWriteTime - Update-Cache -DestinationPath $DestinationPath -Uri $Uri -InputObject $inputObject - } -} - -# The Test-TargetResource function is used to validate if the DestinationPath exists on the machine. -function Test-TargetResource -{ - [CmdletBinding()] - [OutputType([System.Boolean])] - param - ( - [parameter(Mandatory = $true)] - [ValidateNotNullOrEmpty()] - [System.String] - $DestinationPath, - - [parameter(Mandatory = $true)] - [ValidateNotNullOrEmpty()] - [System.String] - $Uri, - - [System.String] - $UserAgent, - - [Microsoft.Management.Infrastructure.CimInstance[]] - $Headers, - - [System.Management.Automation.PSCredential] - $Credential, - + $MatchSource = $true + ) + + # Validate Uri + if (!(Check-UriScheme -uri $Uri -scheme "http") -and !(Check-UriScheme -uri $Uri -scheme "https")) + { + $errorId = "UriValidationFailure"; + $errorMessage = $($LocalizedData.InvalidWebUriError) -f ${Uri} + Throw-InvalidDataException -errorId $errorId -errorMessage $errorMessage + } + + # Validate DestinationPath scheme + if (!(Check-UriScheme -uri $DestinationPath -scheme "file")) + { + $errorMessage = $($LocalizedData.InvalidDestinationPathSchemeError) -f ${DestinationPath} + Throw-InvalidDataException -errorId "DestinationPathSchemeValidationFailure" -errorMessage $errorMessage + } + + # Validate DestinationPath is not UNC path + if ($DestinationPath.StartsWith("\\")) + { + $errorMessage = $($LocalizedData.DestinationPathIsUncError) -f ${DestinationPath} + Throw-InvalidDataException -errorId "DestinationPathIsUncFailure" -errorMessage $errorMessage + } + + # Validate DestinationPath does not contain invalid characters + $invalidCharacters = '*','?','"','<','>','|' + $invalidCharacters | % { + if ($DestinationPath.Contains($_) ){ + $errorMessage = $($LocalizedData.DestinationPathHasInvalidCharactersError) -f ${DestinationPath} + Throw-InvalidDataException -errorId "DestinationPathHasInvalidCharactersError" -errorMessage $errorMessage + } + } + + # Validate DestinationPath does not end with / or \ (Invoke-WebRequest requirement) + if ($DestinationPath.EndsWith('/') -or $DestinationPath.EndsWith('\')){ + $errorMessage = $($LocalizedData.DestinationPathEndsWithInvalidCharacterError) -f ${DestinationPath} + Throw-InvalidDataException -errorId "DestinationPathEndsWithInvalidCharacterError" -errorMessage $errorMessage + } + + # Check whether DestinationPath's parent directory exists. Create if it doesn't. + $destinationPathParent = Split-Path $DestinationPath -Parent + if (!(Test-Path $destinationPathParent)) + { + New-Item -Type Directory -Path $destinationPathParent -Force + } + + # Check whether DestinationPath's leaf is an existing folder + $uriFileName = Split-Path $Uri -Leaf + if (Test-Path $DestinationPath -PathType Container) + { + $DestinationPath = Join-Path $DestinationPath $uriFileName + } + + # Remove DestinationPath and MatchSource from parameters as they are not parameters of Invoke-WebRequest + $PSBoundParameters.Remove("DestinationPath") | Out-Null; + $PSBoundParameters.Remove("MatchSource") | Out-Null; + + # Convert headers to hashtable + $PSBoundParameters.Remove("Headers") | Out-Null; + $headersHashtable = $null + + if ($Headers -ne $null) + { + $headersHashtable = Convert-KeyValuePairArrayToHashtable -array $Headers + } + + # Invoke web request + try + { + Write-Verbose "Downloading $Uri to $DestinationPath" + Invoke-WebRequest @PSBoundParameters -Headers $headersHashtable -outFile $DestinationPath + } + catch [System.OutOfMemoryException] + { + throw "Received OutOfMemoryException. Possible cause is the requested file being too big. $_" + } + catch [System.Exception] + { + throw "Invoking web request failed with error $($_.Exception.Response.StatusCode.Value__): $($_.Exception.Response.StatusDescription)" + } + + # Update cache + if (Test-Path $DestinationPath) + { + $downloadedFile = Get-Item $DestinationPath + $lastWriteTime = $downloadedFile.LastWriteTimeUtc + $inputObject = @{} + $inputObject["LastWriteTime"] = $lastWriteTime + Update-Cache -DestinationPath $DestinationPath -Uri $Uri -InputObject $inputObject + } +} + +# The Test-TargetResource function is used to validate if the DestinationPath exists on the machine. +function Test-TargetResource +{ + [CmdletBinding()] + [OutputType([System.Boolean])] + param + ( + [parameter(Mandatory = $true)] + [ValidateNotNullOrEmpty()] + [System.String] + $DestinationPath, + + [parameter(Mandatory = $true)] + [ValidateNotNullOrEmpty()] + [System.String] + $Uri, + + [System.String] + $UserAgent, + + [Microsoft.Management.Infrastructure.CimInstance[]] + $Headers, + + [System.Management.Automation.PSCredential] + $Credential, + [parameter(Mandatory = $false)] [System.Boolean] - $MatchSource = $true - ) - - # Check whether DestinationPath points to existing file or directory - $fileExists = $false - $uriFileName = Split-Path $Uri -Leaf - $pathItemType = Get-PathItemType -path $DestinationPath - switch($pathItemType) - { - "File" { - Write-Debug "DestinationPath: '$DestinationPath' is existing file on the machine" - - if ($MatchSource) { - $file = Get-Item $DestinationPath - # Getting cache. It's cleared every time user runs Start-DscConfiguration - $cache = Get-Cache -DestinationPath $DestinationPath -Uri $Uri - - if ($cache -ne $null -and ($cache.LastWriteTime -eq $file.LastWriteTimeUtc)) - { - Write-Debug "Cache reflects current state. No need for downloading file." - $fileExists = $true - } - else - { - Write-Debug "Cache is empty or it doesn't reflect current state. File will be downloaded." - } - } else { - Write-Debug "MatchSource is false. No need for downloading file." + $MatchSource = $true + ) + + # Check whether DestinationPath points to existing file or directory + $fileExists = $false + $uriFileName = Split-Path $Uri -Leaf + $pathItemType = Get-PathItemType -path $DestinationPath + switch($pathItemType) + { + "File" { + Write-Debug "DestinationPath: '$DestinationPath' is existing file on the machine" + + if ($MatchSource) { + $file = Get-Item $DestinationPath + # Getting cache. It's cleared every time user runs Start-DscConfiguration + $cache = Get-Cache -DestinationPath $DestinationPath -Uri $Uri + + if ($cache -ne $null -and ($cache.LastWriteTime -eq $file.LastWriteTimeUtc)) + { + Write-Debug "Cache reflects current state. No need for downloading file." + $fileExists = $true + } + else + { + Write-Debug "Cache is empty or it doesn't reflect current state. File will be downloaded." + } + } else { + Write-Debug "Destination file size is not the same as source file. File will be downloaded." [System.Net.WebClient]$wc = [System.Net.WebClient]::New() $wc.OpenRead($URI) - [Long]$bytes_total = $wc.ResponseHeaders["Content-Length"] - if($bytes_total -eq (Get-Item $DestinationPath).Length) - { - $fileExists = $true - } - } - } - - "Directory" { - Write-Debug "DestinationPath: '$DestinationPath' is existing directory on the machine" - $expectedDestinationPath = Join-Path $DestinationPath $uriFileName - - if (Test-Path $expectedDestinationPath) { - if ($MatchSource) { - $file = Get-Item $expectedDestinationPath - $cache = Get-Cache -DestinationPath $expectedDestinationPath -Uri $Uri - if ($cache -ne $null -and ($cache.LastWriteTime -eq $file.LastWriteTimeUtc)) - { - Write-Debug "Cache reflects current state. No need for downloading file." - $fileExists = $true - } - else - { - Write-Debug "Cache is empty or it doesn't reflect current state. File will be downloaded." - } - } else { - Write-Debug "MatchSource is false. No need for downloading file." - $fileExists = $true - } - } - } - - "Other" { - Write-Debug "DestinationPath: '$DestinationPath' has unknown type: '$pathItemType'" - } - - "NotExists" { - Write-Debug "DestinationPath: '$DestinationPath' doesn't exist on the machine" - } - } - - $result = $fileExists - - $result -} - -# Throws terminating error of category InvalidData with specified errorId and errorMessage -function Throw-InvalidDataException -{ - param( - [parameter(Mandatory = $true)] - [System.String] - $errorId, - [parameter(Mandatory = $true)] - [System.String] - $errorMessage - ) - - $errorCategory = [System.Management.Automation.ErrorCategory]::InvalidData - $exception = New-Object System.InvalidOperationException $errorMessage - $errorRecord = New-Object System.Management.Automation.ErrorRecord $exception, $errorId, $errorCategory, $null - throw $errorRecord -} - -# Checks whether given URI represents specific scheme -# Most common schemes: file, http, https, ftp -# We can also specify logical expressions like: [http|https] -function Check-UriScheme -{ - param ( - [parameter(Mandatory = $true)] - [System.String] - $uri, - [parameter(Mandatory = $true)] - [System.String] - $scheme - ) - $newUri = $uri -as [System.URI] - $newUri.AbsoluteURI -ne $null -and $newUri.Scheme -match $scheme -} - -# Gets type of the item which path points to. -# Returns: File, Directory, Other or NotExists -function Get-PathItemType -{ - param ( - [parameter(Mandatory = $true)] - [System.String] - $path - ) - - $type = $null - - # Check whether path exists - if (Test-Path $path) - { - # Check type of the path - $pathItem = Get-Item $path - $pathItemType = $pathItem.GetType().Name - if ($pathItemType -eq "FileInfo") - { - $type = "File" - } - elseif ($pathItemType -eq "DirectoryInfo") - { - $type = "Directory" - } - else - { - $type = "Other" - } - } - else - { - $type = "NotExists" - } - - return $type -} - -# Converts CimInstance array of type KeyValuePair to hashtable -function Convert-KeyValuePairArrayToHashtable -{ - param ( - [parameter(Mandatory = $true)] - [Microsoft.Management.Infrastructure.CimInstance[]] - $array - ) - - $hashtable = @{} - foreach($item in $array) - { - $hashtable += @{$item.Key = $item.Value} - } - - return $hashtable -} - -# Gets cache for specific DestinationPath and Uri -function Get-Cache -{ - param ( - [parameter(Mandatory = $true)] - [ValidateNotNullOrEmpty()] - [System.String] - $DestinationPath, - - [parameter(Mandatory = $true)] - [ValidateNotNullOrEmpty()] - [System.String] - $Uri - ) - - $cacheContent = $null - $key = Get-CacheKey -DestinationPath $DestinationPath -Uri $Uri - $path = Join-Path $script:cacheLocation $key - - Write-Debug "Looking for path $path" - if(!(Test-Path $path)) - { - Write-Debug "No cache found for DestinationPath = $DestinationPath and Uri = $Uri. CacheKey = $key" - $cacheContent = $null - } - else - { - $cacheContent = Import-CliXml $path - Write-Debug "Found cache for DestinationPath = $DestinationPath and Uri = $Uri. CacheKey = $key" - } - - return $cacheContent -} - -# Creates or updates cache for specific DestinationPath and Uri -function Update-Cache -{ - param ( - [parameter(Mandatory = $true)] - [ValidateNotNullOrEmpty()] - [System.String] - $DestinationPath, - - [parameter(Mandatory = $true)] - [ValidateNotNullOrEmpty()] - [System.String] - $Uri, - - [parameter(Mandatory = $true)] - [Object] - $InputObject - ) - - $key = Get-CacheKey -DestinationPath $DestinationPath -Uri $Uri - $path = Join-Path $script:cacheLocation $key - - if(-not (Test-Path $script:cacheLocation)) - { - mkdir $script:cacheLocation | Out-Null - } - - Write-Debug "Updating cache for DestinationPath = $DestinationPath and Uri = $Uri. CacheKey = $key" - Export-CliXml -Path $path -InputObject $InputObject -Force -} - -# Returns cache key for given parameters -function Get-CacheKey -{ - param ( - [parameter(Mandatory = $true)] - [ValidateNotNullOrEmpty()] - [System.String] - $DestinationPath, - - [parameter(Mandatory = $true)] - [ValidateNotNullOrEmpty()] - [System.String] - $Uri - ) - $key = [string]::Join("", @($DestinationPath, $Uri)).GetHashCode().ToString() - return $key -} - -Export-ModuleMember -Function *-TargetResource - - - + [Long]$bytes_total = $wc.ResponseHeaders["Content-Length"] + if($bytes_total -eq (Get-Item $DestinationPath).Length) + { + Write-Debug "MatchSource is false. No need for downloading file." + $fileExists = $true + } + } + } + + "Directory" { + Write-Debug "DestinationPath: '$DestinationPath' is existing directory on the machine" + $expectedDestinationPath = Join-Path $DestinationPath $uriFileName + + if (Test-Path $expectedDestinationPath) { + if ($MatchSource) { + $file = Get-Item $expectedDestinationPath + $cache = Get-Cache -DestinationPath $expectedDestinationPath -Uri $Uri + if ($cache -ne $null -and ($cache.LastWriteTime -eq $file.LastWriteTimeUtc)) + { + Write-Debug "Cache reflects current state. No need for downloading file." + $fileExists = $true + } + else + { + Write-Debug "Cache is empty or it doesn't reflect current state. File will be downloaded." + } + } else { + Write-Debug "MatchSource is false. No need for downloading file." + $fileExists = $true + } + } + } + + "Other" { + Write-Debug "DestinationPath: '$DestinationPath' has unknown type: '$pathItemType'" + } + + "NotExists" { + Write-Debug "DestinationPath: '$DestinationPath' doesn't exist on the machine" + } + } + + $result = $fileExists + + $result +} + +# Throws terminating error of category InvalidData with specified errorId and errorMessage +function Throw-InvalidDataException +{ + param( + [parameter(Mandatory = $true)] + [System.String] + $errorId, + [parameter(Mandatory = $true)] + [System.String] + $errorMessage + ) + + $errorCategory = [System.Management.Automation.ErrorCategory]::InvalidData + $exception = New-Object System.InvalidOperationException $errorMessage + $errorRecord = New-Object System.Management.Automation.ErrorRecord $exception, $errorId, $errorCategory, $null + throw $errorRecord +} + +# Checks whether given URI represents specific scheme +# Most common schemes: file, http, https, ftp +# We can also specify logical expressions like: [http|https] +function Check-UriScheme +{ + param ( + [parameter(Mandatory = $true)] + [System.String] + $uri, + [parameter(Mandatory = $true)] + [System.String] + $scheme + ) + $newUri = $uri -as [System.URI] + $newUri.AbsoluteURI -ne $null -and $newUri.Scheme -match $scheme +} + +# Gets type of the item which path points to. +# Returns: File, Directory, Other or NotExists +function Get-PathItemType +{ + param ( + [parameter(Mandatory = $true)] + [System.String] + $path + ) + + $type = $null + + # Check whether path exists + if (Test-Path $path) + { + # Check type of the path + $pathItem = Get-Item $path + $pathItemType = $pathItem.GetType().Name + if ($pathItemType -eq "FileInfo") + { + $type = "File" + } + elseif ($pathItemType -eq "DirectoryInfo") + { + $type = "Directory" + } + else + { + $type = "Other" + } + } + else + { + $type = "NotExists" + } + + return $type +} + +# Converts CimInstance array of type KeyValuePair to hashtable +function Convert-KeyValuePairArrayToHashtable +{ + param ( + [parameter(Mandatory = $true)] + [Microsoft.Management.Infrastructure.CimInstance[]] + $array + ) + + $hashtable = @{} + foreach($item in $array) + { + $hashtable += @{$item.Key = $item.Value} + } + + return $hashtable +} + +# Gets cache for specific DestinationPath and Uri +function Get-Cache +{ + param ( + [parameter(Mandatory = $true)] + [ValidateNotNullOrEmpty()] + [System.String] + $DestinationPath, + + [parameter(Mandatory = $true)] + [ValidateNotNullOrEmpty()] + [System.String] + $Uri + ) + + $cacheContent = $null + $key = Get-CacheKey -DestinationPath $DestinationPath -Uri $Uri + $path = Join-Path $script:cacheLocation $key + + Write-Debug "Looking for path $path" + if(!(Test-Path $path)) + { + Write-Debug "No cache found for DestinationPath = $DestinationPath and Uri = $Uri. CacheKey = $key" + $cacheContent = $null + } + else + { + $cacheContent = Import-CliXml $path + Write-Debug "Found cache for DestinationPath = $DestinationPath and Uri = $Uri. CacheKey = $key" + } + + return $cacheContent +} + +# Creates or updates cache for specific DestinationPath and Uri +function Update-Cache +{ + param ( + [parameter(Mandatory = $true)] + [ValidateNotNullOrEmpty()] + [System.String] + $DestinationPath, + + [parameter(Mandatory = $true)] + [ValidateNotNullOrEmpty()] + [System.String] + $Uri, + + [parameter(Mandatory = $true)] + [Object] + $InputObject + ) + + $key = Get-CacheKey -DestinationPath $DestinationPath -Uri $Uri + $path = Join-Path $script:cacheLocation $key + + if(-not (Test-Path $script:cacheLocation)) + { + mkdir $script:cacheLocation | Out-Null + } + + Write-Debug "Updating cache for DestinationPath = $DestinationPath and Uri = $Uri. CacheKey = $key" + Export-CliXml -Path $path -InputObject $InputObject -Force +} + +# Returns cache key for given parameters +function Get-CacheKey +{ + param ( + [parameter(Mandatory = $true)] + [ValidateNotNullOrEmpty()] + [System.String] + $DestinationPath, + + [parameter(Mandatory = $true)] + [ValidateNotNullOrEmpty()] + [System.String] + $Uri + ) + $key = [string]::Join("", @($DestinationPath, $Uri)).GetHashCode().ToString() + return $key +} + +Export-ModuleMember -Function *-TargetResource + + + From ebd215a47795a0050326c0935ba12dbb4aea115e Mon Sep 17 00:00:00 2001 From: Tiberriver256 Date: Mon, 7 Mar 2016 20:52:05 -0500 Subject: [PATCH 09/34] Revert "Added appropriate Write-Debug lines" This reverts commit 9896e2cf14eee8ae432ba563e75c07dab8c30443. --- .../MSFT_xRemoteFile/MSFT_xRemoteFile.psm1 | 953 +++++++++--------- 1 file changed, 476 insertions(+), 477 deletions(-) diff --git a/DSCResources/MSFT_xRemoteFile/MSFT_xRemoteFile.psm1 b/DSCResources/MSFT_xRemoteFile/MSFT_xRemoteFile.psm1 index b5dc8f738..b50e8c333 100644 --- a/DSCResources/MSFT_xRemoteFile/MSFT_xRemoteFile.psm1 +++ b/DSCResources/MSFT_xRemoteFile/MSFT_xRemoteFile.psm1 @@ -1,483 +1,482 @@ -data localizedData -{ - # culture="en-US" - ConvertFrom-StringData @' -InvalidWebUriError=Specified URI is not valid: "{0}". Only http and https paths are accepted. -InvalidDestinationPathSchemeError=Specified DestinationPath is not valid: "{0}". DestinationPath should be absolute path. -DestinationPathIsUncError=Specified DestinationPath is not valid: "{0}". DestinationPath should be local path instead of UNC path. -DestinationPathHasInvalidCharactersError=Specified DestinationPath is not valid: "{0}". DestinationPath should be contains following characters: * ? " < > | -DestinationPathEndsWithInvalidCharacterError=Specified DestinationPath is not valid: "{0}". DestinationPath should not end with / or \\ -'@ -} - -# Path where cache will be stored. It's cleared whenever LCM gets new configuration. -$script:cacheLocation = "$env:ProgramData\Microsoft\Windows\PowerShell\Configuration\BuiltinProvCache\MSFT_xRemoteFile" - -# The Get-TargetResource function is used to fetch the status of file specified in DestinationPath on the target machine. -function Get-TargetResource -{ - [CmdletBinding()] - [OutputType([System.Collections.Hashtable])] - param - ( - [parameter(Mandatory = $true)] - [ValidateNotNullOrEmpty()] - [System.String] - $DestinationPath, - - [parameter(Mandatory = $true)] - [ValidateNotNullOrEmpty()] - [System.String] - $Uri - ) - - # Check whether DestinationPath is existing file - $fileExists = $false - $pathItemType = Get-PathItemType -path $DestinationPath - switch($pathItemType) - { - "File" { - Write-Verbose "DestinationPath: '$DestinationPath' is existing file on the machine" - $fileExists = $true - } - - "Directory" { - Write-Verbose "DestinationPath: '$DestinationPath' is existing directory on the machine" - - # If it's existing directory, let's check whether expectedDestinationPath exists - $uriFileName = Split-Path $Uri -Leaf - $expectedDestinationPath = Join-Path $DestinationPath $uriFileName - if (Test-Path $expectedDestinationPath) { - Write-Verbose "File $uriFileName exists in DestinationPath" - $fileExists = $true - } - } - - "Other" { - Write-Verbose "DestinationPath: '$DestinationPath' has unknown type: '$pathItemType'" - } - - "NotExists" { - Write-Verbose "DestinationPath: '$DestinationPath' doesn't exist on the machine" - } - } - - $ensure = "Absent" - if ($fileExists) - { - $ensure = "Present" - } - - $returnValue = @{ - DestinationPath = $DestinationPath - Ensure = $ensure - } - - $returnValue -} - -# The Set-TargetResource function is used to download file found under Uri location to DestinationPath -# Additional parameters can be specified to configure web request -function Set-TargetResource -{ - [CmdletBinding()] - param - ( - [parameter(Mandatory = $true)] - [ValidateNotNullOrEmpty()] - [System.String] - $DestinationPath, - - [parameter(Mandatory = $true)] - [ValidateNotNullOrEmpty()] - [System.String] - $Uri, - - [System.String] - $UserAgent, - - [Microsoft.Management.Infrastructure.CimInstance[]] - $Headers, - - [System.Management.Automation.PSCredential] - $Credential, - +data localizedData +{ + # culture="en-US" + ConvertFrom-StringData @' +InvalidWebUriError=Specified URI is not valid: "{0}". Only http and https paths are accepted. +InvalidDestinationPathSchemeError=Specified DestinationPath is not valid: "{0}". DestinationPath should be absolute path. +DestinationPathIsUncError=Specified DestinationPath is not valid: "{0}". DestinationPath should be local path instead of UNC path. +DestinationPathHasInvalidCharactersError=Specified DestinationPath is not valid: "{0}". DestinationPath should be contains following characters: * ? " < > | +DestinationPathEndsWithInvalidCharacterError=Specified DestinationPath is not valid: "{0}". DestinationPath should not end with / or \\ +'@ +} + +# Path where cache will be stored. It's cleared whenever LCM gets new configuration. +$script:cacheLocation = "$env:ProgramData\Microsoft\Windows\PowerShell\Configuration\BuiltinProvCache\MSFT_xRemoteFile" + +# The Get-TargetResource function is used to fetch the status of file specified in DestinationPath on the target machine. +function Get-TargetResource +{ + [CmdletBinding()] + [OutputType([System.Collections.Hashtable])] + param + ( + [parameter(Mandatory = $true)] + [ValidateNotNullOrEmpty()] + [System.String] + $DestinationPath, + + [parameter(Mandatory = $true)] + [ValidateNotNullOrEmpty()] + [System.String] + $Uri + ) + + # Check whether DestinationPath is existing file + $fileExists = $false + $pathItemType = Get-PathItemType -path $DestinationPath + switch($pathItemType) + { + "File" { + Write-Verbose "DestinationPath: '$DestinationPath' is existing file on the machine" + $fileExists = $true + } + + "Directory" { + Write-Verbose "DestinationPath: '$DestinationPath' is existing directory on the machine" + + # If it's existing directory, let's check whether expectedDestinationPath exists + $uriFileName = Split-Path $Uri -Leaf + $expectedDestinationPath = Join-Path $DestinationPath $uriFileName + if (Test-Path $expectedDestinationPath) { + Write-Verbose "File $uriFileName exists in DestinationPath" + $fileExists = $true + } + } + + "Other" { + Write-Verbose "DestinationPath: '$DestinationPath' has unknown type: '$pathItemType'" + } + + "NotExists" { + Write-Verbose "DestinationPath: '$DestinationPath' doesn't exist on the machine" + } + } + + $ensure = "Absent" + if ($fileExists) + { + $ensure = "Present" + } + + $returnValue = @{ + DestinationPath = $DestinationPath + Ensure = $ensure + } + + $returnValue +} + +# The Set-TargetResource function is used to download file found under Uri location to DestinationPath +# Additional parameters can be specified to configure web request +function Set-TargetResource +{ + [CmdletBinding()] + param + ( + [parameter(Mandatory = $true)] + [ValidateNotNullOrEmpty()] + [System.String] + $DestinationPath, + + [parameter(Mandatory = $true)] + [ValidateNotNullOrEmpty()] + [System.String] + $Uri, + + [System.String] + $UserAgent, + + [Microsoft.Management.Infrastructure.CimInstance[]] + $Headers, + + [System.Management.Automation.PSCredential] + $Credential, + [parameter(Mandatory = $false)] [System.Boolean] - $MatchSource = $true - ) - - # Validate Uri - if (!(Check-UriScheme -uri $Uri -scheme "http") -and !(Check-UriScheme -uri $Uri -scheme "https")) - { - $errorId = "UriValidationFailure"; - $errorMessage = $($LocalizedData.InvalidWebUriError) -f ${Uri} - Throw-InvalidDataException -errorId $errorId -errorMessage $errorMessage - } - - # Validate DestinationPath scheme - if (!(Check-UriScheme -uri $DestinationPath -scheme "file")) - { - $errorMessage = $($LocalizedData.InvalidDestinationPathSchemeError) -f ${DestinationPath} - Throw-InvalidDataException -errorId "DestinationPathSchemeValidationFailure" -errorMessage $errorMessage - } - - # Validate DestinationPath is not UNC path - if ($DestinationPath.StartsWith("\\")) - { - $errorMessage = $($LocalizedData.DestinationPathIsUncError) -f ${DestinationPath} - Throw-InvalidDataException -errorId "DestinationPathIsUncFailure" -errorMessage $errorMessage - } - - # Validate DestinationPath does not contain invalid characters - $invalidCharacters = '*','?','"','<','>','|' - $invalidCharacters | % { - if ($DestinationPath.Contains($_) ){ - $errorMessage = $($LocalizedData.DestinationPathHasInvalidCharactersError) -f ${DestinationPath} - Throw-InvalidDataException -errorId "DestinationPathHasInvalidCharactersError" -errorMessage $errorMessage - } - } - - # Validate DestinationPath does not end with / or \ (Invoke-WebRequest requirement) - if ($DestinationPath.EndsWith('/') -or $DestinationPath.EndsWith('\')){ - $errorMessage = $($LocalizedData.DestinationPathEndsWithInvalidCharacterError) -f ${DestinationPath} - Throw-InvalidDataException -errorId "DestinationPathEndsWithInvalidCharacterError" -errorMessage $errorMessage - } - - # Check whether DestinationPath's parent directory exists. Create if it doesn't. - $destinationPathParent = Split-Path $DestinationPath -Parent - if (!(Test-Path $destinationPathParent)) - { - New-Item -Type Directory -Path $destinationPathParent -Force - } - - # Check whether DestinationPath's leaf is an existing folder - $uriFileName = Split-Path $Uri -Leaf - if (Test-Path $DestinationPath -PathType Container) - { - $DestinationPath = Join-Path $DestinationPath $uriFileName - } - - # Remove DestinationPath and MatchSource from parameters as they are not parameters of Invoke-WebRequest - $PSBoundParameters.Remove("DestinationPath") | Out-Null; - $PSBoundParameters.Remove("MatchSource") | Out-Null; - - # Convert headers to hashtable - $PSBoundParameters.Remove("Headers") | Out-Null; - $headersHashtable = $null - - if ($Headers -ne $null) - { - $headersHashtable = Convert-KeyValuePairArrayToHashtable -array $Headers - } - - # Invoke web request - try - { - Write-Verbose "Downloading $Uri to $DestinationPath" - Invoke-WebRequest @PSBoundParameters -Headers $headersHashtable -outFile $DestinationPath - } - catch [System.OutOfMemoryException] - { - throw "Received OutOfMemoryException. Possible cause is the requested file being too big. $_" - } - catch [System.Exception] - { - throw "Invoking web request failed with error $($_.Exception.Response.StatusCode.Value__): $($_.Exception.Response.StatusDescription)" - } - - # Update cache - if (Test-Path $DestinationPath) - { - $downloadedFile = Get-Item $DestinationPath - $lastWriteTime = $downloadedFile.LastWriteTimeUtc - $inputObject = @{} - $inputObject["LastWriteTime"] = $lastWriteTime - Update-Cache -DestinationPath $DestinationPath -Uri $Uri -InputObject $inputObject - } -} - -# The Test-TargetResource function is used to validate if the DestinationPath exists on the machine. -function Test-TargetResource -{ - [CmdletBinding()] - [OutputType([System.Boolean])] - param - ( - [parameter(Mandatory = $true)] - [ValidateNotNullOrEmpty()] - [System.String] - $DestinationPath, - - [parameter(Mandatory = $true)] - [ValidateNotNullOrEmpty()] - [System.String] - $Uri, - - [System.String] - $UserAgent, - - [Microsoft.Management.Infrastructure.CimInstance[]] - $Headers, - - [System.Management.Automation.PSCredential] - $Credential, - + $MatchSource = $true + ) + + # Validate Uri + if (!(Check-UriScheme -uri $Uri -scheme "http") -and !(Check-UriScheme -uri $Uri -scheme "https")) + { + $errorId = "UriValidationFailure"; + $errorMessage = $($LocalizedData.InvalidWebUriError) -f ${Uri} + Throw-InvalidDataException -errorId $errorId -errorMessage $errorMessage + } + + # Validate DestinationPath scheme + if (!(Check-UriScheme -uri $DestinationPath -scheme "file")) + { + $errorMessage = $($LocalizedData.InvalidDestinationPathSchemeError) -f ${DestinationPath} + Throw-InvalidDataException -errorId "DestinationPathSchemeValidationFailure" -errorMessage $errorMessage + } + + # Validate DestinationPath is not UNC path + if ($DestinationPath.StartsWith("\\")) + { + $errorMessage = $($LocalizedData.DestinationPathIsUncError) -f ${DestinationPath} + Throw-InvalidDataException -errorId "DestinationPathIsUncFailure" -errorMessage $errorMessage + } + + # Validate DestinationPath does not contain invalid characters + $invalidCharacters = '*','?','"','<','>','|' + $invalidCharacters | % { + if ($DestinationPath.Contains($_) ){ + $errorMessage = $($LocalizedData.DestinationPathHasInvalidCharactersError) -f ${DestinationPath} + Throw-InvalidDataException -errorId "DestinationPathHasInvalidCharactersError" -errorMessage $errorMessage + } + } + + # Validate DestinationPath does not end with / or \ (Invoke-WebRequest requirement) + if ($DestinationPath.EndsWith('/') -or $DestinationPath.EndsWith('\')){ + $errorMessage = $($LocalizedData.DestinationPathEndsWithInvalidCharacterError) -f ${DestinationPath} + Throw-InvalidDataException -errorId "DestinationPathEndsWithInvalidCharacterError" -errorMessage $errorMessage + } + + # Check whether DestinationPath's parent directory exists. Create if it doesn't. + $destinationPathParent = Split-Path $DestinationPath -Parent + if (!(Test-Path $destinationPathParent)) + { + New-Item -Type Directory -Path $destinationPathParent -Force + } + + # Check whether DestinationPath's leaf is an existing folder + $uriFileName = Split-Path $Uri -Leaf + if (Test-Path $DestinationPath -PathType Container) + { + $DestinationPath = Join-Path $DestinationPath $uriFileName + } + + # Remove DestinationPath and MatchSource from parameters as they are not parameters of Invoke-WebRequest + $PSBoundParameters.Remove("DestinationPath") | Out-Null; + $PSBoundParameters.Remove("MatchSource") | Out-Null; + + # Convert headers to hashtable + $PSBoundParameters.Remove("Headers") | Out-Null; + $headersHashtable = $null + + if ($Headers -ne $null) + { + $headersHashtable = Convert-KeyValuePairArrayToHashtable -array $Headers + } + + # Invoke web request + try + { + Write-Verbose "Downloading $Uri to $DestinationPath" + Invoke-WebRequest @PSBoundParameters -Headers $headersHashtable -outFile $DestinationPath + } + catch [System.OutOfMemoryException] + { + throw "Received OutOfMemoryException. Possible cause is the requested file being too big. $_" + } + catch [System.Exception] + { + throw "Invoking web request failed with error $($_.Exception.Response.StatusCode.Value__): $($_.Exception.Response.StatusDescription)" + } + + # Update cache + if (Test-Path $DestinationPath) + { + $downloadedFile = Get-Item $DestinationPath + $lastWriteTime = $downloadedFile.LastWriteTimeUtc + $inputObject = @{} + $inputObject["LastWriteTime"] = $lastWriteTime + Update-Cache -DestinationPath $DestinationPath -Uri $Uri -InputObject $inputObject + } +} + +# The Test-TargetResource function is used to validate if the DestinationPath exists on the machine. +function Test-TargetResource +{ + [CmdletBinding()] + [OutputType([System.Boolean])] + param + ( + [parameter(Mandatory = $true)] + [ValidateNotNullOrEmpty()] + [System.String] + $DestinationPath, + + [parameter(Mandatory = $true)] + [ValidateNotNullOrEmpty()] + [System.String] + $Uri, + + [System.String] + $UserAgent, + + [Microsoft.Management.Infrastructure.CimInstance[]] + $Headers, + + [System.Management.Automation.PSCredential] + $Credential, + [parameter(Mandatory = $false)] [System.Boolean] - $MatchSource = $true - ) - - # Check whether DestinationPath points to existing file or directory - $fileExists = $false - $uriFileName = Split-Path $Uri -Leaf - $pathItemType = Get-PathItemType -path $DestinationPath - switch($pathItemType) - { - "File" { - Write-Debug "DestinationPath: '$DestinationPath' is existing file on the machine" - - if ($MatchSource) { - $file = Get-Item $DestinationPath - # Getting cache. It's cleared every time user runs Start-DscConfiguration - $cache = Get-Cache -DestinationPath $DestinationPath -Uri $Uri - - if ($cache -ne $null -and ($cache.LastWriteTime -eq $file.LastWriteTimeUtc)) - { - Write-Debug "Cache reflects current state. No need for downloading file." - $fileExists = $true - } - else - { - Write-Debug "Cache is empty or it doesn't reflect current state. File will be downloaded." - } - } else { - Write-Debug "Destination file size is not the same as source file. File will be downloaded." + $MatchSource = $true + ) + + # Check whether DestinationPath points to existing file or directory + $fileExists = $false + $uriFileName = Split-Path $Uri -Leaf + $pathItemType = Get-PathItemType -path $DestinationPath + switch($pathItemType) + { + "File" { + Write-Debug "DestinationPath: '$DestinationPath' is existing file on the machine" + + if ($MatchSource) { + $file = Get-Item $DestinationPath + # Getting cache. It's cleared every time user runs Start-DscConfiguration + $cache = Get-Cache -DestinationPath $DestinationPath -Uri $Uri + + if ($cache -ne $null -and ($cache.LastWriteTime -eq $file.LastWriteTimeUtc)) + { + Write-Debug "Cache reflects current state. No need for downloading file." + $fileExists = $true + } + else + { + Write-Debug "Cache is empty or it doesn't reflect current state. File will be downloaded." + } + } else { + Write-Debug "MatchSource is false. No need for downloading file." [System.Net.WebClient]$wc = [System.Net.WebClient]::New() $wc.OpenRead($URI) - [Long]$bytes_total = $wc.ResponseHeaders["Content-Length"] - if($bytes_total -eq (Get-Item $DestinationPath).Length) - { - Write-Debug "MatchSource is false. No need for downloading file." - $fileExists = $true - } - } - } - - "Directory" { - Write-Debug "DestinationPath: '$DestinationPath' is existing directory on the machine" - $expectedDestinationPath = Join-Path $DestinationPath $uriFileName - - if (Test-Path $expectedDestinationPath) { - if ($MatchSource) { - $file = Get-Item $expectedDestinationPath - $cache = Get-Cache -DestinationPath $expectedDestinationPath -Uri $Uri - if ($cache -ne $null -and ($cache.LastWriteTime -eq $file.LastWriteTimeUtc)) - { - Write-Debug "Cache reflects current state. No need for downloading file." - $fileExists = $true - } - else - { - Write-Debug "Cache is empty or it doesn't reflect current state. File will be downloaded." - } - } else { - Write-Debug "MatchSource is false. No need for downloading file." - $fileExists = $true - } - } - } - - "Other" { - Write-Debug "DestinationPath: '$DestinationPath' has unknown type: '$pathItemType'" - } - - "NotExists" { - Write-Debug "DestinationPath: '$DestinationPath' doesn't exist on the machine" - } - } - - $result = $fileExists - - $result -} - -# Throws terminating error of category InvalidData with specified errorId and errorMessage -function Throw-InvalidDataException -{ - param( - [parameter(Mandatory = $true)] - [System.String] - $errorId, - [parameter(Mandatory = $true)] - [System.String] - $errorMessage - ) - - $errorCategory = [System.Management.Automation.ErrorCategory]::InvalidData - $exception = New-Object System.InvalidOperationException $errorMessage - $errorRecord = New-Object System.Management.Automation.ErrorRecord $exception, $errorId, $errorCategory, $null - throw $errorRecord -} - -# Checks whether given URI represents specific scheme -# Most common schemes: file, http, https, ftp -# We can also specify logical expressions like: [http|https] -function Check-UriScheme -{ - param ( - [parameter(Mandatory = $true)] - [System.String] - $uri, - [parameter(Mandatory = $true)] - [System.String] - $scheme - ) - $newUri = $uri -as [System.URI] - $newUri.AbsoluteURI -ne $null -and $newUri.Scheme -match $scheme -} - -# Gets type of the item which path points to. -# Returns: File, Directory, Other or NotExists -function Get-PathItemType -{ - param ( - [parameter(Mandatory = $true)] - [System.String] - $path - ) - - $type = $null - - # Check whether path exists - if (Test-Path $path) - { - # Check type of the path - $pathItem = Get-Item $path - $pathItemType = $pathItem.GetType().Name - if ($pathItemType -eq "FileInfo") - { - $type = "File" - } - elseif ($pathItemType -eq "DirectoryInfo") - { - $type = "Directory" - } - else - { - $type = "Other" - } - } - else - { - $type = "NotExists" - } - - return $type -} - -# Converts CimInstance array of type KeyValuePair to hashtable -function Convert-KeyValuePairArrayToHashtable -{ - param ( - [parameter(Mandatory = $true)] - [Microsoft.Management.Infrastructure.CimInstance[]] - $array - ) - - $hashtable = @{} - foreach($item in $array) - { - $hashtable += @{$item.Key = $item.Value} - } - - return $hashtable -} - -# Gets cache for specific DestinationPath and Uri -function Get-Cache -{ - param ( - [parameter(Mandatory = $true)] - [ValidateNotNullOrEmpty()] - [System.String] - $DestinationPath, - - [parameter(Mandatory = $true)] - [ValidateNotNullOrEmpty()] - [System.String] - $Uri - ) - - $cacheContent = $null - $key = Get-CacheKey -DestinationPath $DestinationPath -Uri $Uri - $path = Join-Path $script:cacheLocation $key - - Write-Debug "Looking for path $path" - if(!(Test-Path $path)) - { - Write-Debug "No cache found for DestinationPath = $DestinationPath and Uri = $Uri. CacheKey = $key" - $cacheContent = $null - } - else - { - $cacheContent = Import-CliXml $path - Write-Debug "Found cache for DestinationPath = $DestinationPath and Uri = $Uri. CacheKey = $key" - } - - return $cacheContent -} - -# Creates or updates cache for specific DestinationPath and Uri -function Update-Cache -{ - param ( - [parameter(Mandatory = $true)] - [ValidateNotNullOrEmpty()] - [System.String] - $DestinationPath, - - [parameter(Mandatory = $true)] - [ValidateNotNullOrEmpty()] - [System.String] - $Uri, - - [parameter(Mandatory = $true)] - [Object] - $InputObject - ) - - $key = Get-CacheKey -DestinationPath $DestinationPath -Uri $Uri - $path = Join-Path $script:cacheLocation $key - - if(-not (Test-Path $script:cacheLocation)) - { - mkdir $script:cacheLocation | Out-Null - } - - Write-Debug "Updating cache for DestinationPath = $DestinationPath and Uri = $Uri. CacheKey = $key" - Export-CliXml -Path $path -InputObject $InputObject -Force -} - -# Returns cache key for given parameters -function Get-CacheKey -{ - param ( - [parameter(Mandatory = $true)] - [ValidateNotNullOrEmpty()] - [System.String] - $DestinationPath, - - [parameter(Mandatory = $true)] - [ValidateNotNullOrEmpty()] - [System.String] - $Uri - ) - $key = [string]::Join("", @($DestinationPath, $Uri)).GetHashCode().ToString() - return $key -} - -Export-ModuleMember -Function *-TargetResource - - - + [Long]$bytes_total = $wc.ResponseHeaders["Content-Length"] + if($bytes_total -eq (Get-Item $DestinationPath).Length) + { + $fileExists = $true + } + } + } + + "Directory" { + Write-Debug "DestinationPath: '$DestinationPath' is existing directory on the machine" + $expectedDestinationPath = Join-Path $DestinationPath $uriFileName + + if (Test-Path $expectedDestinationPath) { + if ($MatchSource) { + $file = Get-Item $expectedDestinationPath + $cache = Get-Cache -DestinationPath $expectedDestinationPath -Uri $Uri + if ($cache -ne $null -and ($cache.LastWriteTime -eq $file.LastWriteTimeUtc)) + { + Write-Debug "Cache reflects current state. No need for downloading file." + $fileExists = $true + } + else + { + Write-Debug "Cache is empty or it doesn't reflect current state. File will be downloaded." + } + } else { + Write-Debug "MatchSource is false. No need for downloading file." + $fileExists = $true + } + } + } + + "Other" { + Write-Debug "DestinationPath: '$DestinationPath' has unknown type: '$pathItemType'" + } + + "NotExists" { + Write-Debug "DestinationPath: '$DestinationPath' doesn't exist on the machine" + } + } + + $result = $fileExists + + $result +} + +# Throws terminating error of category InvalidData with specified errorId and errorMessage +function Throw-InvalidDataException +{ + param( + [parameter(Mandatory = $true)] + [System.String] + $errorId, + [parameter(Mandatory = $true)] + [System.String] + $errorMessage + ) + + $errorCategory = [System.Management.Automation.ErrorCategory]::InvalidData + $exception = New-Object System.InvalidOperationException $errorMessage + $errorRecord = New-Object System.Management.Automation.ErrorRecord $exception, $errorId, $errorCategory, $null + throw $errorRecord +} + +# Checks whether given URI represents specific scheme +# Most common schemes: file, http, https, ftp +# We can also specify logical expressions like: [http|https] +function Check-UriScheme +{ + param ( + [parameter(Mandatory = $true)] + [System.String] + $uri, + [parameter(Mandatory = $true)] + [System.String] + $scheme + ) + $newUri = $uri -as [System.URI] + $newUri.AbsoluteURI -ne $null -and $newUri.Scheme -match $scheme +} + +# Gets type of the item which path points to. +# Returns: File, Directory, Other or NotExists +function Get-PathItemType +{ + param ( + [parameter(Mandatory = $true)] + [System.String] + $path + ) + + $type = $null + + # Check whether path exists + if (Test-Path $path) + { + # Check type of the path + $pathItem = Get-Item $path + $pathItemType = $pathItem.GetType().Name + if ($pathItemType -eq "FileInfo") + { + $type = "File" + } + elseif ($pathItemType -eq "DirectoryInfo") + { + $type = "Directory" + } + else + { + $type = "Other" + } + } + else + { + $type = "NotExists" + } + + return $type +} + +# Converts CimInstance array of type KeyValuePair to hashtable +function Convert-KeyValuePairArrayToHashtable +{ + param ( + [parameter(Mandatory = $true)] + [Microsoft.Management.Infrastructure.CimInstance[]] + $array + ) + + $hashtable = @{} + foreach($item in $array) + { + $hashtable += @{$item.Key = $item.Value} + } + + return $hashtable +} + +# Gets cache for specific DestinationPath and Uri +function Get-Cache +{ + param ( + [parameter(Mandatory = $true)] + [ValidateNotNullOrEmpty()] + [System.String] + $DestinationPath, + + [parameter(Mandatory = $true)] + [ValidateNotNullOrEmpty()] + [System.String] + $Uri + ) + + $cacheContent = $null + $key = Get-CacheKey -DestinationPath $DestinationPath -Uri $Uri + $path = Join-Path $script:cacheLocation $key + + Write-Debug "Looking for path $path" + if(!(Test-Path $path)) + { + Write-Debug "No cache found for DestinationPath = $DestinationPath and Uri = $Uri. CacheKey = $key" + $cacheContent = $null + } + else + { + $cacheContent = Import-CliXml $path + Write-Debug "Found cache for DestinationPath = $DestinationPath and Uri = $Uri. CacheKey = $key" + } + + return $cacheContent +} + +# Creates or updates cache for specific DestinationPath and Uri +function Update-Cache +{ + param ( + [parameter(Mandatory = $true)] + [ValidateNotNullOrEmpty()] + [System.String] + $DestinationPath, + + [parameter(Mandatory = $true)] + [ValidateNotNullOrEmpty()] + [System.String] + $Uri, + + [parameter(Mandatory = $true)] + [Object] + $InputObject + ) + + $key = Get-CacheKey -DestinationPath $DestinationPath -Uri $Uri + $path = Join-Path $script:cacheLocation $key + + if(-not (Test-Path $script:cacheLocation)) + { + mkdir $script:cacheLocation | Out-Null + } + + Write-Debug "Updating cache for DestinationPath = $DestinationPath and Uri = $Uri. CacheKey = $key" + Export-CliXml -Path $path -InputObject $InputObject -Force +} + +# Returns cache key for given parameters +function Get-CacheKey +{ + param ( + [parameter(Mandatory = $true)] + [ValidateNotNullOrEmpty()] + [System.String] + $DestinationPath, + + [parameter(Mandatory = $true)] + [ValidateNotNullOrEmpty()] + [System.String] + $Uri + ) + $key = [string]::Join("", @($DestinationPath, $Uri)).GetHashCode().ToString() + return $key +} + +Export-ModuleMember -Function *-TargetResource + + + From ec17986167cb21f77ee5d6f157d89d2a78695782 Mon Sep 17 00:00:00 2001 From: Tiberriver256 Date: Mon, 7 Mar 2016 20:52:08 -0500 Subject: [PATCH 10/34] Revert "Added size comparison" This reverts commit 2486d2cc37ff983a11ab46dc8931e724f8017eab. --- DSCResources/MSFT_xRemoteFile/MSFT_xRemoteFile.psm1 | 8 +------- 1 file changed, 1 insertion(+), 7 deletions(-) diff --git a/DSCResources/MSFT_xRemoteFile/MSFT_xRemoteFile.psm1 b/DSCResources/MSFT_xRemoteFile/MSFT_xRemoteFile.psm1 index b50e8c333..c6568808f 100644 --- a/DSCResources/MSFT_xRemoteFile/MSFT_xRemoteFile.psm1 +++ b/DSCResources/MSFT_xRemoteFile/MSFT_xRemoteFile.psm1 @@ -253,13 +253,7 @@ function Test-TargetResource } } else { Write-Debug "MatchSource is false. No need for downloading file." - [System.Net.WebClient]$wc = [System.Net.WebClient]::New() - $wc.OpenRead($URI) - [Long]$bytes_total = $wc.ResponseHeaders["Content-Length"] - if($bytes_total -eq (Get-Item $DestinationPath).Length) - { - $fileExists = $true - } + $fileExists = $true } } From 34e33b7e5e15a4cfa4c8b287904fc5f8bf67dfbe Mon Sep 17 00:00:00 2001 From: Tiberriver256 Date: Tue, 8 Mar 2016 22:09:23 -0500 Subject: [PATCH 11/34] Added check for file size --- DSCResources/MSFT_xRemoteFile/MSFT_xRemoteFile.psm1 | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/DSCResources/MSFT_xRemoteFile/MSFT_xRemoteFile.psm1 b/DSCResources/MSFT_xRemoteFile/MSFT_xRemoteFile.psm1 index c6568808f..5c4a37b68 100644 --- a/DSCResources/MSFT_xRemoteFile/MSFT_xRemoteFile.psm1 +++ b/DSCResources/MSFT_xRemoteFile/MSFT_xRemoteFile.psm1 @@ -191,8 +191,10 @@ function Set-TargetResource { $downloadedFile = Get-Item $DestinationPath $lastWriteTime = $downloadedFile.LastWriteTimeUtc + $filesize = $downloadedFile.Length $inputObject = @{} $inputObject["LastWriteTime"] = $lastWriteTime + $inputObject["FileSize"] = $filesize Update-Cache -DestinationPath $DestinationPath -Uri $Uri -InputObject $inputObject } } @@ -242,7 +244,7 @@ function Test-TargetResource # Getting cache. It's cleared every time user runs Start-DscConfiguration $cache = Get-Cache -DestinationPath $DestinationPath -Uri $Uri - if ($cache -ne $null -and ($cache.LastWriteTime -eq $file.LastWriteTimeUtc)) + if ($cache -ne $null -and ($cache.LastWriteTime -eq $file.LastWriteTimeUtc) -and ($cache.FileSize -eq $file.Length)) { Write-Debug "Cache reflects current state. No need for downloading file." $fileExists = $true From 2a5a398267222fdef2fc97b236ea645931e368c5 Mon Sep 17 00:00:00 2001 From: Berhe Abrha Date: Fri, 11 Mar 2016 11:42:25 -0800 Subject: [PATCH 12/34] Added pullserver deployement example verification tests --- .../PullServerSetupTests.ps1 | 135 ++++++++++++++++++ README.md | 6 + 2 files changed, 141 insertions(+) create mode 100644 Examples/PullServerDeployementVerificationTest/PullServerSetupTests.ps1 diff --git a/Examples/PullServerDeployementVerificationTest/PullServerSetupTests.ps1 b/Examples/PullServerDeployementVerificationTest/PullServerSetupTests.ps1 new file mode 100644 index 000000000..3ee1ab642 --- /dev/null +++ b/Examples/PullServerDeployementVerificationTest/PullServerSetupTests.ps1 @@ -0,0 +1,135 @@ + +<# + * + * Once you setup your pullserver(V2), run the following set of tests on the pullserver machine to verify if the pullserver is setup properly and ready to go. + * This test assumes default values are used during deployement for the location of web.config and pull server URL. + * If default values are not used during deployement, please update these values in the 'BeforeAll' block accordingly. + * + #> + + +Describe PullServerInstallationTests{ + +BeforeAll{ + + # UPDATE THE PULLSERVER URL, If it is different from the default value. + $pullserverURL = "http://$(hostname):8080/PSDSCPullServer/PSDSCPullserver.svc" + + # UPDATE THE LOCATION OF WEB.CONFIG, if it is differnet from the default path. + $script:defaultPullServerConfigFile = "$($env:SystemDrive)\inetpub\wwwroot\psdscpullserver\web.config" + + $skip = $false + if (-not (Test-Path $defaultPullServerConfigFile)) + { + $skip = $true + Write-Error "No pullserver web.config found." -ErrorAction Stop + } + $script:webConfigXml = [xml](cat $script:defaultPullServerConfigFile) + + # RegKey info. + $regFileName = "RegistrationKeys.txt" + $regKeyElement = $webConfigXml.SelectNodes("//appSettings/add[@key = 'RegistrationKeyPath']") + $fullRegKeyPath = Join-Path $regKeyElement.value $regFileName + $regKeyContent = cat $fullRegKeyPath + + # Configuration repository info. + $configurationPathElement = $webConfigXml.SelectNodes("//appSettings/add[@key = 'ConfigurationPath']") + $script:configurationRepository = $configurationPathElement.value + +} + +It "Verify RegistrationKeyFile exist" -skip:$skip{ + + $regKey = $webConfigXml.SelectNodes("//appSettings/add[@key = 'RegistrationKeyPath']") + + if (Test-path (Join-Path $regKey.value $regFileName)){ + Write-Verbose "Registration key file found." + } + else + { + throw "RegistrationKeyFile NOT found. Make sure registration key file is placed on the location specified on the web.config of the pullserver." + } + } + +<# + # Verify module and configuration repository referenced on the web.config file exist. + #> + It "Verify configuration and module repository folders exist" -skip:$skip{ + + $modulePathElement = $webConfigXml.SelectNodes("//appSettings/add[@key = 'ModulePath']") + Test-Path ($modulePathElement.value) | Should Be $true "Module repository path referenced on web.config does not exist on the disk" + Test-Path $script:configurationRepository | Should Be $true "Module repository path referenced on web.config does not exist on the disk" +} + +<# +# +# Verify the server URL is up and running. +#> + It "Verify server is up and running" -skip:$skip{ + $response = Invoke-WebRequest -Uri $pullserverURL -UseBasicParsing + $response.StatusCode | Should Be 200 "Server response should be ok" + } + + <# + # Verify pull works on the current evironement by pulling a (No-OP) configuration from the pullserver. + # + #> + It "Verify pull end to end works" -skip:$skip{ + +# Sample test meta-configuration +$configName = "PullServerSetUpTest" +[DscLocalConfigurationManager()] +Configuration PullServerSetUpTestMetaConfig +{ + Settings + { + RefreshMode = "PULL" + + } + ConfigurationRepositoryWeb ConfigurationManager + { + ServerURL = $pullserverURL + AllowUnsecureConnection = $true # Remove this if you are using https + RegistrationKey = $regKeyContent + ConfigurationNames = @($configName) + } + +} + +PullServerSetUpTestMetaConfig -OutputPath .\PullServerSetUpTestMetaConfig +slcm -path .\PullServerSetUpTestMetaConfig -Verbose -force + + +$name = glcm |% ConfigurationDownloadManagers|% ConfigurationNames +$name | Should Be $configName + + +# Sample test configuration +Configuration NoOpConfig +{ + Import-DscResource –ModuleName 'PSDesiredStateConfiguration' + Node ($configName) + { + Script script + { + GetScript = "@{}" + SetScript = "{}" + TestScript = ‘if ($false) { return $true } else {return $false}‘ + } + } +} + +# Create a mof file copy it to +NoOpConfig -OutputPath $configurationRepository -Verbose + +# Create checksum +New-DscChecksum $configurationRepository -Verbose -Force + +# pull configuration from the server. +Update-DscConfiguration -Wait -Verbose + +$confignameSet = Get-DscConfiguration | % ConfigurationName +$confignameSet | Should Be "NoOpConfig" "Configuration is not set properly" + } + +} \ No newline at end of file diff --git a/README.md b/README.md index b1206d0fa..f96243b18 100644 --- a/README.md +++ b/README.md @@ -164,6 +164,8 @@ Note: _the xWindowsOptionalFeature is only supported on Windows client or Window ### Unreleased +* Added Pester tests to validate pullserver deployement. + ### 3.7.0.0 * xService: @@ -293,3 +295,7 @@ This configuration will install a .msi package and verify the package using the ### Sample1.ps4 installs a package that uses an .exe file This configuration will install a .exe package and verify the package using the product ID and package name and requires credentials to read the share and install the package. It also uses custom registry values to check for the package presence. + +### Pester tests to validate pullserver deployement. + +[Pullserver Validation Tests](Examples/PullServerDeployementVerificationTest) \ No newline at end of file From bb5ca35b0eed7f1d58ddf66c282ca77695002121 Mon Sep 17 00:00:00 2001 From: megamorf Date: Sat, 12 Mar 2016 20:33:47 +0100 Subject: [PATCH 13/34] fixed typo and corrected term just a minor typo correction & UPN stands for User Principal Name not Universal Principal Name --- README.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index b1206d0fa..63f88d1a1 100644 --- a/README.md +++ b/README.md @@ -41,7 +41,7 @@ If the **DestinationType** is set to `Directory` (default), then the ZIP file sp * **PhysicalPath**: Folder location where the content of the web service resides. * **State**: State of the web service: { Started | Stopped } * **ModulePath**: Folder location where DSC resources are stored. -* **ConfiguraitonPath**: Folder location where DSC configurations are stored. +* **ConfigurationPath**: Folder location where DSC configurations are stored. * **IsComplianceServer**: Determines whether the web service endpoint exposes compliance data. * **Ensure**: Ensures that the web service is **Present** or **Absent** @@ -120,7 +120,7 @@ Local accounts may be specified in one of the following ways: * The account name scoped to the explicit machine name (eg. myserver\users or myserver\username). * The account name scoped using the explicit local machine qualifier (eg. .\users or .\username). -Domain members may be specified using domain\name or Universal Principal Name (UPN) formatting. The following illustrates the various formats +Domain members may be specified using domain\name or User Principal Name (UPN) formatting. The following illustrates the various formats * Domain joined machines: mydomain\myserver or myserver@mydomain.com * Domain user accounts: mydomain\username or username@mydomain.com From 9c67f3f26dbeadc88ddef28f2d89b35b1b26b581 Mon Sep 17 00:00:00 2001 From: Ray Hayes Date: Mon, 14 Mar 2016 09:21:22 -0700 Subject: [PATCH 14/34] Remove reference to compliance server and fix database defaults. --- .../MSFT_xDSCWebService.psm1 | 153 ++++++------------ 1 file changed, 48 insertions(+), 105 deletions(-) diff --git a/DSCResources/MSFT_xDSCWebService/MSFT_xDSCWebService.psm1 b/DSCResources/MSFT_xDSCWebService/MSFT_xDSCWebService.psm1 index a4c1d9b9c..38aa9b82e 100644 --- a/DSCResources/MSFT_xDSCWebService/MSFT_xDSCWebService.psm1 +++ b/DSCResources/MSFT_xDSCWebService/MSFT_xDSCWebService.psm1 @@ -94,7 +94,7 @@ function Set-TargetResource [string]$EndpointName, # Port number of the DSC Pull Server IIS Endpoint - [Uint32]$Port = $( if ($IsComplianceServer) { 7070 } else { 8080 } ), + [Uint32]$Port = 8080, # Physical path for the IIS Endpoint on the machine (usually under inetpub) [string]$PhysicalPath = "$env:SystemDrive\inetpub\$EndpointName", @@ -116,14 +116,11 @@ function Set-TargetResource # Location on the disk where the Configuration is stored [string]$ConfigurationPath = "$env:PROGRAMFILES\WindowsPowerShell\DscService\Configuration", - # Is the endpoint for a DSC Compliance Server - [boolean]$IsComplianceServer, - # Location on the disk where the RegistrationKeys file is stored [string]$RegistrationKeyPath = "$env:PROGRAMFILES\WindowsPowerShell\DscService", # Add the IISSelfSignedCertModule native module to prevent self-signed certs being rejected. - [boolean]$AcceptSelfSignedCertificates + [boolean]$AcceptSelfSignedCertificates = $true ) # Initialize with default values @@ -150,41 +147,18 @@ function Set-TargetResource $IsBlue = $true; } + $isDownlevelOfBlue = $false; + if($os.Major -eq 6 -and $os.Minor -lt 3) + { + $isDownlevelOfBlue= $true; + } + # Use Pull Server values for defaults $webConfigFileName = "$pathPullServer\PSDSCPullServer.config" $svcFileName = "$pathPullServer\PSDSCPullServer.svc" $pswsMofFileName = "$pathPullServer\PSDSCPullServer.mof" $pswsDispatchFileName = "$pathPullServer\PSDSCPullServer.xml" - # Update only if Compliance Server install is requested - if ($IsComplianceServer) - { - $webConfigFileName = "$pathPullServer\PSDSCComplianceServer.config" - $svcFileName = "$pathPullServer\PSDSCComplianceServer.svc" - $pswsMofFileName = "$pathPullServer\PSDSCComplianceServer.mof" - $pswsDispatchFileName = "$pathPullServer\PSDSCComplianceServer.xml" - } - - # check for the existance of Windows authentication, this is needed for the Compliance Server - if(($Ensure -eq "Present")) - { - Write-Verbose "Check IIS Windows Authentication" - # only important if Present, Get-WindowsFeature works under 2008 R2 and newer - if ((Get-WindowsFeature -name Web-Windows-Auth | Where Installed).count -eq 0) - { - # enable the feature - # Checking for Windows Server 2008 R2: - if([Environment]::OSVersion.Version.ToString().StartsWith("6.1.")) - { - Add-WindowsFeature -Name Web-Windows-Auth - } - else - { - Install-WindowsFeature -Name Web-Windows-Auth - } - } - } - # ============ Absent block to remove existing site ========= if(($Ensure -eq "Absent")) { @@ -200,7 +174,6 @@ function Set-TargetResource return } # =========================================================== - Write-Verbose "Create the IIS endpoint" PSWSIISEndpoint\New-PSWSEndpoint -site $EndpointName ` @@ -223,68 +196,67 @@ function Set-TargetResource Update-LocationTagInApplicationHostConfigForAuthentication -WebSite $EndpointName -Authentication "basic" Update-LocationTagInApplicationHostConfigForAuthentication -WebSite $EndpointName -Authentication "windows" - if ($IsBlue) { Write-Verbose "Set values into the web.config that define the repository for BLUE OS" - #PSWSIISEndpoint\Set-AppSettingsInWebconfig -path $PhysicalPath -key "dbprovider" -value $eseprovider - #PSWSIISEndpoint\Set-AppSettingsInWebconfig -path $PhysicalPath -key "dbconnectionstr"-value $esedatabase - #ESE database is not present in current build PSWSIISEndpoint\Set-AppSettingsInWebconfig -path $PhysicalPath -key "dbprovider" -value $jet4provider PSWSIISEndpoint\Set-AppSettingsInWebconfig -path $PhysicalPath -key "dbconnectionstr" -value $jet4database Set-BindingRedirectSettingInWebConfig -path $PhysicalPath } else { - Write-Verbose "Set values into the web.config that define the repository for non-BLUE Downlevel OS" - $repository = Join-Path "$rootDataPath" "Devices.mdb" - Copy-Item "$pathPullServer\Devices.mdb" $repository -Force + if($isDownlevelOfBlue) + { + Write-Verbose "Set values into the web.config that define the repository for non-BLUE Downlevel OS" + $repository = Join-Path "$rootDataPath" "Devices.mdb" + Copy-Item "$pathPullServer\Devices.mdb" $repository -Force - PSWSIISEndpoint\Set-AppSettingsInWebconfig -path $PhysicalPath -key "dbprovider" -value $jet4provider - PSWSIISEndpoint\Set-AppSettingsInWebconfig -path $PhysicalPath -key "dbconnectionstr" -value $jet4database - } + PSWSIISEndpoint\Set-AppSettingsInWebconfig -path $PhysicalPath -key "dbprovider" -value $jet4provider + PSWSIISEndpoint\Set-AppSettingsInWebconfig -path $PhysicalPath -key "dbconnectionstr" -value $jet4database + } + else + { + Write-Verbose "Set values into the web.config that define the repository later than BLUE OS" + Write-Verbose "Only ESENT is supported on Windows Server 2016" - if ($IsComplianceServer) - { - Write-Verbose "Compliance Server: Set values into the web.config that indicate this is the admin endpoint" - PSWSIISEndpoint\Set-AppSettingsInWebconfig -path $PhysicalPath -key "AdminEndPoint" -value "true" + PSWSIISEndpoint\Set-AppSettingsInWebconfig -path $PhysicalPath -key "dbprovider" -value $eseprovider + PSWSIISEndpoint\Set-AppSettingsInWebconfig -path $PhysicalPath -key "dbconnectionstr"-value $esedatabase + } } - else - { - Write-Verbose "Pull Server: Set values into the web.config that indicate the location of repository, configuration, modules" - # Create the application data directory calculated above - $null = New-Item -path $rootDataPath -itemType "directory" -Force + Write-Verbose "Pull Server: Set values into the web.config that indicate the location of repository, configuration, modules" + + # Create the application data directory calculated above + $null = New-Item -path $rootDataPath -itemType "directory" -Force - $repository = Join-Path $rootDataPath "Devices.mdb" - Copy-Item "$pathPullServer\Devices.mdb" $repository -Force + $repository = Join-Path $rootDataPath "Devices.mdb" + Copy-Item "$pathPullServer\Devices.mdb" $repository -Force - $null = New-Item -path "$ConfigurationPath" -itemType "directory" -Force + $null = New-Item -path "$ConfigurationPath" -itemType "directory" -Force - PSWSIISEndpoint\Set-AppSettingsInWebconfig -path $PhysicalPath -key "ConfigurationPath" -value $ConfigurationPath + PSWSIISEndpoint\Set-AppSettingsInWebconfig -path $PhysicalPath -key "ConfigurationPath" -value $ConfigurationPath - $null = New-Item -path "$ModulePath" -itemType "directory" -Force + $null = New-Item -path "$ModulePath" -itemType "directory" -Force - PSWSIISEndpoint\Set-AppSettingsInWebconfig -path $PhysicalPath -key "ModulePath" -value $ModulePath + PSWSIISEndpoint\Set-AppSettingsInWebconfig -path $PhysicalPath -key "ModulePath" -value $ModulePath - $null = New-Item -path "$RegistrationKeyPath" -itemType "directory" -Force + $null = New-Item -path "$RegistrationKeyPath" -itemType "directory" -Force - PSWSIISEndpoint\Set-AppSettingsInWebconfig -path $PhysicalPath -key "RegistrationKeyPath" -value $RegistrationKeyPath + PSWSIISEndpoint\Set-AppSettingsInWebconfig -path $PhysicalPath -key "RegistrationKeyPath" -value $RegistrationKeyPath - if($AcceptSelfSignedCertificates) - { - Copy-Item "$pathPullServer\IISSelfSignedCertModule.dll" $env:windir\System32\inetsrv -Force - Copy-Item "$env:windir\SysWOW64\WindowsPowerShell\v1.0\Modules\PSDesiredStateConfiguration\PullServer\IISSelfSignedCertModule.dll" $env:windir\SysWOW64\inetsrv -Force + if($AcceptSelfSignedCertificates) + { + Copy-Item "$pathPullServer\IISSelfSignedCertModule.dll" $env:windir\System32\inetsrv -Force + Copy-Item "$env:windir\SysWOW64\WindowsPowerShell\v1.0\Modules\PSDesiredStateConfiguration\PullServer\IISSelfSignedCertModule.dll" $env:windir\SysWOW64\inetsrv -Force - & $script:appCmd install module /name:"IISSelfSignedCertModule(32bit)" /image:$env:windir\SysWOW64\inetsrv\IISSelfSignedCertModule.dll /add:false /lock:false - & $script:appCmd add module /name:"IISSelfSignedCertModule(32bit)" /app.name:"PSDSCPullServer/" - } - else + & $script:appCmd install module /name:"IISSelfSignedCertModule(32bit)" /image:$env:windir\SysWOW64\inetsrv\IISSelfSignedCertModule.dll /add:false /lock:false + & $script:appCmd add module /name:"IISSelfSignedCertModule(32bit)" /app.name:"PSDSCPullServer/" + } + else + { + if($AcceptSelfSignedCertificates -and ($AcceptSelfSignedCertificates -eq $false)) { - if($AcceptSelfSignedCertificates -and ($AcceptSelfSignedCertificates -eq $false)) - { - & $script:appCmd delete module /name:"IISSelfSignedCertModule(32bit)" /app.name:"PSDSCPullServer/" - } + & $script:appCmd delete module /name:"IISSelfSignedCertModule(32bit)" /app.name:"PSDSCPullServer/" } } } @@ -301,7 +273,7 @@ function Test-TargetResource [string]$EndpointName, # Port number of the DSC Pull Server IIS Endpoint - [Uint32]$Port = $( if ($IsComplianceServer) { 7070 } else { 8080 } ), + [Uint32]$Port = 8080, # Physical path for the IIS Endpoint on the machine (usually under inetpub) [string]$PhysicalPath = "$env:SystemDrive\inetpub\$EndpointName", @@ -323,14 +295,8 @@ function Test-TargetResource # Location on the disk where the Configuration is stored [string]$ConfigurationPath = "$env:PROGRAMFILES\WindowsPowerShell\DscService\Configuration", - # Is the endpoint for a DSC Compliance Server - [boolean]$IsComplianceServer, - # Location on the disk where the RegistrationKeys file is stored - [string]$RegistrationKeyPath, - - # Are self-signed certs being accepted for client auth. - [boolean]$AcceptSelfSignedCertificates + [string]$RegistrationKeyPath ) $desiredConfigurationMatch = $true; @@ -361,19 +327,6 @@ function Test-TargetResource } # the other case is: Ensure and exist, we continue with more checks - # check for the existance of Windows authentication, this is needed for the Compliance Server - if(($Ensure -eq "Present")) - { - Write-Verbose "Check IIS Windows Authentication" - # only important if Present, Get-WindowsFeature works under 2008 R2 and newer - if ((Get-WindowsFeature -name Web-Windows-Auth | Where Installed).count -eq 0) - { - $DesiredConfigurationMatch = $false - Write-Verbose "Required Windows authentication is not installed, does not match the desired state." - break - } - } - Write-Verbose "Check Port" $actualPort = $website.bindings.Collection[0].bindingInformation.Split(":")[1] if ($Port -ne $actualPort) @@ -432,16 +385,6 @@ function Test-TargetResource break } } - - Write-Verbose "Check AcceptSelfSignedCertificates" - if ($AcceptSelfSignedCertificates) - { - if (-not (Test-WebConfigModulesSetting -WebConfigFullPath $webConfigFullPath -ModuleName "IISSelfSignedCertModule(32bit)" -ExpectedInstallationStatus $AcceptSelfSignedCertificates)) - { - $DesiredConfigurationMatch = $false - break - } - } } $stop = $false } From 20f590ca55e36ec193351fbd0da5ab79363251a3 Mon Sep 17 00:00:00 2001 From: Ray Hayes Date: Mon, 14 Mar 2016 09:21:46 -0700 Subject: [PATCH 15/34] Remove compliance server. Remove compliance server. --- DSCResources/MSFT_xDSCWebService/MSFT_xDSCWebService.Schema.mof | 1 - 1 file changed, 1 deletion(-) diff --git a/DSCResources/MSFT_xDSCWebService/MSFT_xDSCWebService.Schema.mof b/DSCResources/MSFT_xDSCWebService/MSFT_xDSCWebService.Schema.mof index c75dde570..b32eeb4b2 100644 --- a/DSCResources/MSFT_xDSCWebService/MSFT_xDSCWebService.Schema.mof +++ b/DSCResources/MSFT_xDSCWebService/MSFT_xDSCWebService.Schema.mof @@ -9,7 +9,6 @@ class MSFT_xDSCWebService : OMI_BaseResource [write,ValueMap{"Started","Stopped"},Values{"Started", "Stopped"}] string State; [write] string ModulePath; [write] string ConfigurationPath; - [write] boolean IsComplianceServer; [read] string DSCServerUrl; [write] string RegistrationKeyPath; [write] boolean AcceptSelfSignedCertificates; From 9b1a39cd17a9f4dd5705fdfed082fd8325685f07 Mon Sep 17 00:00:00 2001 From: Ray Hayes Date: Mon, 14 Mar 2016 09:45:45 -0700 Subject: [PATCH 16/34] Fix typo in the test resource Fixed typo in the test resource --- .../MSFT_xDSCWebService/MSFT_xDSCWebService.psm1 | 15 ++++++++++++++- 1 file changed, 14 insertions(+), 1 deletion(-) diff --git a/DSCResources/MSFT_xDSCWebService/MSFT_xDSCWebService.psm1 b/DSCResources/MSFT_xDSCWebService/MSFT_xDSCWebService.psm1 index 38aa9b82e..f714bce0f 100644 --- a/DSCResources/MSFT_xDSCWebService/MSFT_xDSCWebService.psm1 +++ b/DSCResources/MSFT_xDSCWebService/MSFT_xDSCWebService.psm1 @@ -296,7 +296,10 @@ function Test-TargetResource [string]$ConfigurationPath = "$env:PROGRAMFILES\WindowsPowerShell\DscService\Configuration", # Location on the disk where the RegistrationKeys file is stored - [string]$RegistrationKeyPath + [string]$RegistrationKeyPath, + + # Add the IISSelfSignedCertModule native module to prevent self-signed certs being rejected. + [boolean]$AcceptSelfSignedCertificates ) $desiredConfigurationMatch = $true; @@ -385,6 +388,16 @@ function Test-TargetResource break } } + + Write-Verbose "Check AcceptSelfSignedCertificates" + if ($AcceptSelfSignedCertificates) + { + if (-not (Test-WebConfigModulesSetting -WebConfigFullPath $webConfigFullPath -ModuleName "IISSelfSignedCertModule(32bit)" -ExpectedInstallationStatus $AcceptSelfSignedCertificates)) + { + $DesiredConfigurationMatch = $false + break + } + } } $stop = $false } From d78299710ec26b8983083909a54daa58defe6cd8 Mon Sep 17 00:00:00 2001 From: Berhe Abrha Date: Mon, 14 Mar 2016 11:43:46 -0700 Subject: [PATCH 17/34] Fixing typos --- .../PullServerSetupTests.ps1 | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Examples/PullServerDeployementVerificationTest/PullServerSetupTests.ps1 b/Examples/PullServerDeployementVerificationTest/PullServerSetupTests.ps1 index 3ee1ab642..97ce21f4a 100644 --- a/Examples/PullServerDeployementVerificationTest/PullServerSetupTests.ps1 +++ b/Examples/PullServerDeployementVerificationTest/PullServerSetupTests.ps1 @@ -2,8 +2,8 @@ <# * * Once you setup your pullserver(V2), run the following set of tests on the pullserver machine to verify if the pullserver is setup properly and ready to go. - * This test assumes default values are used during deployement for the location of web.config and pull server URL. - * If default values are not used during deployement, please update these values in the 'BeforeAll' block accordingly. + * This test assumes default values are used during deployment for the location of web.config and pull server URL. + * If default values are not used during deployment , please update these values in the 'BeforeAll' block accordingly. * #> From bc63deac484a2cf44b03b4c9ff0adf617c5846fb Mon Sep 17 00:00:00 2001 From: Berhe Abrha Date: Mon, 14 Mar 2016 12:45:33 -0700 Subject: [PATCH 18/34] Rename a folder and corresponding readme.txt --- .../PullServerSetupTests.ps1 | 0 README.md | 2 +- 2 files changed, 1 insertion(+), 1 deletion(-) rename Examples/{PullServerDeployementVerificationTest => PullServerDeploymentVerificationTest}/PullServerSetupTests.ps1 (100%) diff --git a/Examples/PullServerDeployementVerificationTest/PullServerSetupTests.ps1 b/Examples/PullServerDeploymentVerificationTest/PullServerSetupTests.ps1 similarity index 100% rename from Examples/PullServerDeployementVerificationTest/PullServerSetupTests.ps1 rename to Examples/PullServerDeploymentVerificationTest/PullServerSetupTests.ps1 diff --git a/README.md b/README.md index f96243b18..f5e58a4be 100644 --- a/README.md +++ b/README.md @@ -298,4 +298,4 @@ This configuration will install a .exe package and verify the package using the ### Pester tests to validate pullserver deployement. -[Pullserver Validation Tests](Examples/PullServerDeployementVerificationTest) \ No newline at end of file +[Pullserver Validation Tests](Examples/PullServerDeploymentVerificationTest) \ No newline at end of file From 28a68ad974807d4bdfb8211bd8829439f8006eb4 Mon Sep 17 00:00:00 2001 From: Ray Hayes Date: Mon, 14 Mar 2016 12:51:25 -0700 Subject: [PATCH 19/34] Revert "Fix typo in the test resource" This reverts commit 9b1a39cd17a9f4dd5705fdfed082fd8325685f07. --- .../MSFT_xDSCWebService/MSFT_xDSCWebService.psm1 | 15 +-------------- 1 file changed, 1 insertion(+), 14 deletions(-) diff --git a/DSCResources/MSFT_xDSCWebService/MSFT_xDSCWebService.psm1 b/DSCResources/MSFT_xDSCWebService/MSFT_xDSCWebService.psm1 index f714bce0f..38aa9b82e 100644 --- a/DSCResources/MSFT_xDSCWebService/MSFT_xDSCWebService.psm1 +++ b/DSCResources/MSFT_xDSCWebService/MSFT_xDSCWebService.psm1 @@ -296,10 +296,7 @@ function Test-TargetResource [string]$ConfigurationPath = "$env:PROGRAMFILES\WindowsPowerShell\DscService\Configuration", # Location on the disk where the RegistrationKeys file is stored - [string]$RegistrationKeyPath, - - # Add the IISSelfSignedCertModule native module to prevent self-signed certs being rejected. - [boolean]$AcceptSelfSignedCertificates + [string]$RegistrationKeyPath ) $desiredConfigurationMatch = $true; @@ -388,16 +385,6 @@ function Test-TargetResource break } } - - Write-Verbose "Check AcceptSelfSignedCertificates" - if ($AcceptSelfSignedCertificates) - { - if (-not (Test-WebConfigModulesSetting -WebConfigFullPath $webConfigFullPath -ModuleName "IISSelfSignedCertModule(32bit)" -ExpectedInstallationStatus $AcceptSelfSignedCertificates)) - { - $DesiredConfigurationMatch = $false - break - } - } } $stop = $false } From cab7a642ff459436f709741193e63308ae25f13c Mon Sep 17 00:00:00 2001 From: Ray Hayes Date: Mon, 14 Mar 2016 12:51:35 -0700 Subject: [PATCH 20/34] Revert "Remove compliance server." This reverts commit 20f590ca55e36ec193351fbd0da5ab79363251a3. --- DSCResources/MSFT_xDSCWebService/MSFT_xDSCWebService.Schema.mof | 1 + 1 file changed, 1 insertion(+) diff --git a/DSCResources/MSFT_xDSCWebService/MSFT_xDSCWebService.Schema.mof b/DSCResources/MSFT_xDSCWebService/MSFT_xDSCWebService.Schema.mof index b32eeb4b2..c75dde570 100644 --- a/DSCResources/MSFT_xDSCWebService/MSFT_xDSCWebService.Schema.mof +++ b/DSCResources/MSFT_xDSCWebService/MSFT_xDSCWebService.Schema.mof @@ -9,6 +9,7 @@ class MSFT_xDSCWebService : OMI_BaseResource [write,ValueMap{"Started","Stopped"},Values{"Started", "Stopped"}] string State; [write] string ModulePath; [write] string ConfigurationPath; + [write] boolean IsComplianceServer; [read] string DSCServerUrl; [write] string RegistrationKeyPath; [write] boolean AcceptSelfSignedCertificates; From c8e5772f67f3c62bd9d2bc034e98e3f941d9201f Mon Sep 17 00:00:00 2001 From: Ray Hayes Date: Mon, 14 Mar 2016 12:51:38 -0700 Subject: [PATCH 21/34] Revert "Remove reference to compliance server and fix database defaults." This reverts commit 9c67f3f26dbeadc88ddef28f2d89b35b1b26b581. --- .../MSFT_xDSCWebService.psm1 | 153 ++++++++++++------ 1 file changed, 105 insertions(+), 48 deletions(-) diff --git a/DSCResources/MSFT_xDSCWebService/MSFT_xDSCWebService.psm1 b/DSCResources/MSFT_xDSCWebService/MSFT_xDSCWebService.psm1 index 38aa9b82e..a4c1d9b9c 100644 --- a/DSCResources/MSFT_xDSCWebService/MSFT_xDSCWebService.psm1 +++ b/DSCResources/MSFT_xDSCWebService/MSFT_xDSCWebService.psm1 @@ -94,7 +94,7 @@ function Set-TargetResource [string]$EndpointName, # Port number of the DSC Pull Server IIS Endpoint - [Uint32]$Port = 8080, + [Uint32]$Port = $( if ($IsComplianceServer) { 7070 } else { 8080 } ), # Physical path for the IIS Endpoint on the machine (usually under inetpub) [string]$PhysicalPath = "$env:SystemDrive\inetpub\$EndpointName", @@ -116,11 +116,14 @@ function Set-TargetResource # Location on the disk where the Configuration is stored [string]$ConfigurationPath = "$env:PROGRAMFILES\WindowsPowerShell\DscService\Configuration", + # Is the endpoint for a DSC Compliance Server + [boolean]$IsComplianceServer, + # Location on the disk where the RegistrationKeys file is stored [string]$RegistrationKeyPath = "$env:PROGRAMFILES\WindowsPowerShell\DscService", # Add the IISSelfSignedCertModule native module to prevent self-signed certs being rejected. - [boolean]$AcceptSelfSignedCertificates = $true + [boolean]$AcceptSelfSignedCertificates ) # Initialize with default values @@ -147,18 +150,41 @@ function Set-TargetResource $IsBlue = $true; } - $isDownlevelOfBlue = $false; - if($os.Major -eq 6 -and $os.Minor -lt 3) - { - $isDownlevelOfBlue= $true; - } - # Use Pull Server values for defaults $webConfigFileName = "$pathPullServer\PSDSCPullServer.config" $svcFileName = "$pathPullServer\PSDSCPullServer.svc" $pswsMofFileName = "$pathPullServer\PSDSCPullServer.mof" $pswsDispatchFileName = "$pathPullServer\PSDSCPullServer.xml" + # Update only if Compliance Server install is requested + if ($IsComplianceServer) + { + $webConfigFileName = "$pathPullServer\PSDSCComplianceServer.config" + $svcFileName = "$pathPullServer\PSDSCComplianceServer.svc" + $pswsMofFileName = "$pathPullServer\PSDSCComplianceServer.mof" + $pswsDispatchFileName = "$pathPullServer\PSDSCComplianceServer.xml" + } + + # check for the existance of Windows authentication, this is needed for the Compliance Server + if(($Ensure -eq "Present")) + { + Write-Verbose "Check IIS Windows Authentication" + # only important if Present, Get-WindowsFeature works under 2008 R2 and newer + if ((Get-WindowsFeature -name Web-Windows-Auth | Where Installed).count -eq 0) + { + # enable the feature + # Checking for Windows Server 2008 R2: + if([Environment]::OSVersion.Version.ToString().StartsWith("6.1.")) + { + Add-WindowsFeature -Name Web-Windows-Auth + } + else + { + Install-WindowsFeature -Name Web-Windows-Auth + } + } + } + # ============ Absent block to remove existing site ========= if(($Ensure -eq "Absent")) { @@ -174,6 +200,7 @@ function Set-TargetResource return } # =========================================================== + Write-Verbose "Create the IIS endpoint" PSWSIISEndpoint\New-PSWSEndpoint -site $EndpointName ` @@ -196,67 +223,68 @@ function Set-TargetResource Update-LocationTagInApplicationHostConfigForAuthentication -WebSite $EndpointName -Authentication "basic" Update-LocationTagInApplicationHostConfigForAuthentication -WebSite $EndpointName -Authentication "windows" + if ($IsBlue) { Write-Verbose "Set values into the web.config that define the repository for BLUE OS" + #PSWSIISEndpoint\Set-AppSettingsInWebconfig -path $PhysicalPath -key "dbprovider" -value $eseprovider + #PSWSIISEndpoint\Set-AppSettingsInWebconfig -path $PhysicalPath -key "dbconnectionstr"-value $esedatabase + #ESE database is not present in current build PSWSIISEndpoint\Set-AppSettingsInWebconfig -path $PhysicalPath -key "dbprovider" -value $jet4provider PSWSIISEndpoint\Set-AppSettingsInWebconfig -path $PhysicalPath -key "dbconnectionstr" -value $jet4database Set-BindingRedirectSettingInWebConfig -path $PhysicalPath } else { - if($isDownlevelOfBlue) - { - Write-Verbose "Set values into the web.config that define the repository for non-BLUE Downlevel OS" - $repository = Join-Path "$rootDataPath" "Devices.mdb" - Copy-Item "$pathPullServer\Devices.mdb" $repository -Force - - PSWSIISEndpoint\Set-AppSettingsInWebconfig -path $PhysicalPath -key "dbprovider" -value $jet4provider - PSWSIISEndpoint\Set-AppSettingsInWebconfig -path $PhysicalPath -key "dbconnectionstr" -value $jet4database - } - else - { - Write-Verbose "Set values into the web.config that define the repository later than BLUE OS" - Write-Verbose "Only ESENT is supported on Windows Server 2016" + Write-Verbose "Set values into the web.config that define the repository for non-BLUE Downlevel OS" + $repository = Join-Path "$rootDataPath" "Devices.mdb" + Copy-Item "$pathPullServer\Devices.mdb" $repository -Force - PSWSIISEndpoint\Set-AppSettingsInWebconfig -path $PhysicalPath -key "dbprovider" -value $eseprovider - PSWSIISEndpoint\Set-AppSettingsInWebconfig -path $PhysicalPath -key "dbconnectionstr"-value $esedatabase - } + PSWSIISEndpoint\Set-AppSettingsInWebconfig -path $PhysicalPath -key "dbprovider" -value $jet4provider + PSWSIISEndpoint\Set-AppSettingsInWebconfig -path $PhysicalPath -key "dbconnectionstr" -value $jet4database } - Write-Verbose "Pull Server: Set values into the web.config that indicate the location of repository, configuration, modules" + if ($IsComplianceServer) + { + Write-Verbose "Compliance Server: Set values into the web.config that indicate this is the admin endpoint" + PSWSIISEndpoint\Set-AppSettingsInWebconfig -path $PhysicalPath -key "AdminEndPoint" -value "true" + } + else + { + Write-Verbose "Pull Server: Set values into the web.config that indicate the location of repository, configuration, modules" - # Create the application data directory calculated above - $null = New-Item -path $rootDataPath -itemType "directory" -Force + # Create the application data directory calculated above + $null = New-Item -path $rootDataPath -itemType "directory" -Force - $repository = Join-Path $rootDataPath "Devices.mdb" - Copy-Item "$pathPullServer\Devices.mdb" $repository -Force + $repository = Join-Path $rootDataPath "Devices.mdb" + Copy-Item "$pathPullServer\Devices.mdb" $repository -Force - $null = New-Item -path "$ConfigurationPath" -itemType "directory" -Force + $null = New-Item -path "$ConfigurationPath" -itemType "directory" -Force - PSWSIISEndpoint\Set-AppSettingsInWebconfig -path $PhysicalPath -key "ConfigurationPath" -value $ConfigurationPath + PSWSIISEndpoint\Set-AppSettingsInWebconfig -path $PhysicalPath -key "ConfigurationPath" -value $ConfigurationPath - $null = New-Item -path "$ModulePath" -itemType "directory" -Force + $null = New-Item -path "$ModulePath" -itemType "directory" -Force - PSWSIISEndpoint\Set-AppSettingsInWebconfig -path $PhysicalPath -key "ModulePath" -value $ModulePath + PSWSIISEndpoint\Set-AppSettingsInWebconfig -path $PhysicalPath -key "ModulePath" -value $ModulePath - $null = New-Item -path "$RegistrationKeyPath" -itemType "directory" -Force + $null = New-Item -path "$RegistrationKeyPath" -itemType "directory" -Force - PSWSIISEndpoint\Set-AppSettingsInWebconfig -path $PhysicalPath -key "RegistrationKeyPath" -value $RegistrationKeyPath + PSWSIISEndpoint\Set-AppSettingsInWebconfig -path $PhysicalPath -key "RegistrationKeyPath" -value $RegistrationKeyPath - if($AcceptSelfSignedCertificates) - { - Copy-Item "$pathPullServer\IISSelfSignedCertModule.dll" $env:windir\System32\inetsrv -Force - Copy-Item "$env:windir\SysWOW64\WindowsPowerShell\v1.0\Modules\PSDesiredStateConfiguration\PullServer\IISSelfSignedCertModule.dll" $env:windir\SysWOW64\inetsrv -Force + if($AcceptSelfSignedCertificates) + { + Copy-Item "$pathPullServer\IISSelfSignedCertModule.dll" $env:windir\System32\inetsrv -Force + Copy-Item "$env:windir\SysWOW64\WindowsPowerShell\v1.0\Modules\PSDesiredStateConfiguration\PullServer\IISSelfSignedCertModule.dll" $env:windir\SysWOW64\inetsrv -Force - & $script:appCmd install module /name:"IISSelfSignedCertModule(32bit)" /image:$env:windir\SysWOW64\inetsrv\IISSelfSignedCertModule.dll /add:false /lock:false - & $script:appCmd add module /name:"IISSelfSignedCertModule(32bit)" /app.name:"PSDSCPullServer/" - } - else - { - if($AcceptSelfSignedCertificates -and ($AcceptSelfSignedCertificates -eq $false)) + & $script:appCmd install module /name:"IISSelfSignedCertModule(32bit)" /image:$env:windir\SysWOW64\inetsrv\IISSelfSignedCertModule.dll /add:false /lock:false + & $script:appCmd add module /name:"IISSelfSignedCertModule(32bit)" /app.name:"PSDSCPullServer/" + } + else { - & $script:appCmd delete module /name:"IISSelfSignedCertModule(32bit)" /app.name:"PSDSCPullServer/" + if($AcceptSelfSignedCertificates -and ($AcceptSelfSignedCertificates -eq $false)) + { + & $script:appCmd delete module /name:"IISSelfSignedCertModule(32bit)" /app.name:"PSDSCPullServer/" + } } } } @@ -273,7 +301,7 @@ function Test-TargetResource [string]$EndpointName, # Port number of the DSC Pull Server IIS Endpoint - [Uint32]$Port = 8080, + [Uint32]$Port = $( if ($IsComplianceServer) { 7070 } else { 8080 } ), # Physical path for the IIS Endpoint on the machine (usually under inetpub) [string]$PhysicalPath = "$env:SystemDrive\inetpub\$EndpointName", @@ -295,8 +323,14 @@ function Test-TargetResource # Location on the disk where the Configuration is stored [string]$ConfigurationPath = "$env:PROGRAMFILES\WindowsPowerShell\DscService\Configuration", + # Is the endpoint for a DSC Compliance Server + [boolean]$IsComplianceServer, + # Location on the disk where the RegistrationKeys file is stored - [string]$RegistrationKeyPath + [string]$RegistrationKeyPath, + + # Are self-signed certs being accepted for client auth. + [boolean]$AcceptSelfSignedCertificates ) $desiredConfigurationMatch = $true; @@ -327,6 +361,19 @@ function Test-TargetResource } # the other case is: Ensure and exist, we continue with more checks + # check for the existance of Windows authentication, this is needed for the Compliance Server + if(($Ensure -eq "Present")) + { + Write-Verbose "Check IIS Windows Authentication" + # only important if Present, Get-WindowsFeature works under 2008 R2 and newer + if ((Get-WindowsFeature -name Web-Windows-Auth | Where Installed).count -eq 0) + { + $DesiredConfigurationMatch = $false + Write-Verbose "Required Windows authentication is not installed, does not match the desired state." + break + } + } + Write-Verbose "Check Port" $actualPort = $website.bindings.Collection[0].bindingInformation.Split(":")[1] if ($Port -ne $actualPort) @@ -385,6 +432,16 @@ function Test-TargetResource break } } + + Write-Verbose "Check AcceptSelfSignedCertificates" + if ($AcceptSelfSignedCertificates) + { + if (-not (Test-WebConfigModulesSetting -WebConfigFullPath $webConfigFullPath -ModuleName "IISSelfSignedCertModule(32bit)" -ExpectedInstallationStatus $AcceptSelfSignedCertificates)) + { + $DesiredConfigurationMatch = $false + break + } + } } $stop = $false } From bea576c8ddda974dc45e648f919ad822dae913b4 Mon Sep 17 00:00:00 2001 From: Narine Mossikyan Date: Mon, 14 Mar 2016 13:07:06 -0700 Subject: [PATCH 22/34] script to package dsc modules and configuration and publish on dsc pull server --- .../PublishModulesAndMofsToPullServer.ps1 | 129 ++++++++++++++++++ DSCPullServer/README.md | Bin 0 -> 334 bytes 2 files changed, 129 insertions(+) create mode 100644 DSCPullServer/PublishModulesAndMofsToPullServer.ps1 create mode 100644 DSCPullServer/README.md diff --git a/DSCPullServer/PublishModulesAndMofsToPullServer.ps1 b/DSCPullServer/PublishModulesAndMofsToPullServer.ps1 new file mode 100644 index 000000000..cb5c55760 --- /dev/null +++ b/DSCPullServer/PublishModulesAndMofsToPullServer.ps1 @@ -0,0 +1,129 @@ +# A tool to use to package DSC modules and mof configuration document and publish them on enterprise DSC pull server in the required format + +param( + +[Parameter(Mandatory=$True)] +[string]$Source = $pwd, # The folder that contains the configuration mof documents and modules to be published on pull server. Everything in this folder will be packaged and published. +[switch]$Force, #switch to overwrite the module if $Source is provided and a different version of the module presents in powershell module path +[string[]]$ModuleNameList # optional parameter to package modules listed in $ListModuleNames based on powershell module path content + +) + +#Create a working directory +$tempFolder = "$pwd\temp" +New-Item -Path $tempFolder -ItemType Directory -Force -ErrorAction SilentlyContinue + +#Copy the mof documents from the $Source to working dir +Copy-Item -Path "$Source\*.mof" -Destination $tempFolder -Force -Verbose + +#Package the modules using powershell module path +function CreateZipFromPSModulePath +{ + param($listModuleNames, $destination) + # Move all required modules from powershell module path to a temp folder and package them + if(($listModuleNames -eq $null) -or ($listModuleNames.Count -eq 0)) + { + Write-Host "No additional modules are specified to be packaged." + } + foreach ($module in $listModuleNames) + { + $allVersions = Get-Module -Name $module -ListAvailable -Verbose + #package all versions of the module + foreach($moduleVersion in $allVersions) + { + $allModuleFiles = Get-ChildItem $moduleVersion.ModuleBase + $name = $moduleVersion.Name + $source = "$destination\$name" + New-Item -Path "$destination\$name" -ItemType Directory -Force -Verbose + foreach ($item in $allModuleFiles) + { + Copy-Item -Path $item.FullName -Recurse -Destination $source -Force + } + #Create package zip + Compress-Archive -Path $source -DestinationPath "$source.zip" -Verbose -Force + $version = $moduleVersion.Version.ToString() + $newName = "$destination\$name" + "_" + "$version" + ".zip" + # Rename the module folder to contain the version info. + if(Test-Path($newName)) + { + Remove-Item $newName -Recurse -Force + } + Rename-Item -Path "$source.zip" -NewName $newName -Force + + } + } + +} +#Function to package modules using a given folder after installing to ps module path. +function CreateZipFromSource +{ + param($source, $destination) + # for each module under $Source folder create a zip package that has the same name as the folder. + $allModulesInSource = Get-ChildItem $source -Directory + $modules = @() + + foreach ($item in $allModulesInSource) + { + $name = $item.Name + $alreadyExists = Get-Module -Name $name -ListAvailable -Verbose + if(($alreadyExists -eq $null) -or ($Force)) + { + #install the modules into powershell module path and overwrite the content + Copy-Item $item.FullName -Recurse -Force -Destination "$env:ProgramFiles\WindowsPowerShell\Modules" -Verbose + } + else + { + Write-Host "Skipping module overwrite. Module with the name $name already exists. Please specify -Force to overwrite the module with the version located in $source or remove the module folder from $source." + } + $modules+= @("$name") + } + #Package the module in $destination + CreateZipFromPSModulePath -listModuleNames $modules -destination $destination +} + + +# Deploy modules to the pullsever repository. +function PublishModulesAndChecksum +{ + param($source) + # Check if the current machine is a server sku. + $moduleRepository = "$env:ProgramFiles\WindowsPowerShell\DscService\Modules" + if( (Get-Module ServerManager -ListAvailable) -and (Test-Path ($moduleRepository))) + { + Copy "$source\*.zip*" $moduleRepository -Force -Verbose + } + else + { + Write-Host "Copying modules to pullserver module repository skipped because the machine is not a server sku or Pull server endpoint is not deployed." -Fore Yellow + } + +} + +# function deploy configuratoin and thier checksum. +function PublishMofDocuments +{ + param($source) + # Check if the current machine is a server sku. + $mofRepository = "$env:ProgramFiles\WindowsPowerShell\DscService\Configuration" + if( (Get-Module ServerManager -ListAvailable) -and (Test-Path ($mofRepository)) ) + { + Copy-Item "$source\*.mof*" $mofRepository -Force -Verbose + } + else + { + Write-Host "Copying configuration(s) to pullserver configuration repository skipped because the machine is not a server sku or Pull server endpoint is not deployed." -Fore Yellow + } +} + +#Start Deployment! +Write-Host "Start deployment" +CreateZipFromPSModulePath -listModuleNames $ModuleNameList -destination $tempFolder +CreateZipFromSource -source $Source -destination $tempFolder +# Generate the checkSum file for all the zip and mof files. +New-DSCCheckSum $tempFolder -Force +# Publish mof and modules to pull server repositories +PublishModulesAndChecksum -source $tempFolder +PublishMofDocuments -source $tempFolder +#Deployment is complete! +Remove-Item -Path $tempFolder -Recurse -Force -ErrorAction SilentlyContinue +Write-Host "End deployment" \ No newline at end of file diff --git a/DSCPullServer/README.md b/DSCPullServer/README.md new file mode 100644 index 0000000000000000000000000000000000000000..924cac1c61055844a88b6c881006bb667fc61d71 GIT binary patch literal 334 zcmZ9HTMEK35Jm5|;2r}0x(i)^&=r(6hG1$+AEKLAPezMHN;Apa$J}{6cXB$a(m^N9 zN_>^P2Hos*YLs==q*{?W!k&3Wc+sl2-UQ3RDOgs=Z9=~|J33jd`Il~uQ%n7LpK%Ic zgQ=p;bKn_#M(J(7QxD$g!Wk?}SUI(@5{#_JN>P%#ufFWm^GEWQ485gE+{*j6@1D;8 V?6S?0Ysv0)CrO7-LO*J&jozc)KXCv6 literal 0 HcmV?d00001 From d352be7c82fe7a3aae69e4eef8d3812ea1a1e092 Mon Sep 17 00:00:00 2001 From: Narine Mossikyan Date: Mon, 14 Mar 2016 15:01:29 -0700 Subject: [PATCH 23/34] Fixed the tabs to spaces --- DSCPullServer/PublishModulesAndMofsToPullServer.ps1 | 11 +++-------- 1 file changed, 3 insertions(+), 8 deletions(-) diff --git a/DSCPullServer/PublishModulesAndMofsToPullServer.ps1 b/DSCPullServer/PublishModulesAndMofsToPullServer.ps1 index cb5c55760..7cf83d403 100644 --- a/DSCPullServer/PublishModulesAndMofsToPullServer.ps1 +++ b/DSCPullServer/PublishModulesAndMofsToPullServer.ps1 @@ -31,16 +31,11 @@ function CreateZipFromPSModulePath #package all versions of the module foreach($moduleVersion in $allVersions) { - $allModuleFiles = Get-ChildItem $moduleVersion.ModuleBase $name = $moduleVersion.Name $source = "$destination\$name" - New-Item -Path "$destination\$name" -ItemType Directory -Force -Verbose - foreach ($item in $allModuleFiles) - { - Copy-Item -Path $item.FullName -Recurse -Destination $source -Force - } #Create package zip - Compress-Archive -Path $source -DestinationPath "$source.zip" -Verbose -Force + $path = $moduleVersion.ModuleBase + Compress-Archive -Path "$path\*" -DestinationPath "$source.zip" -Verbose -Force $version = $moduleVersion.Version.ToString() $newName = "$destination\$name" + "_" + "$version" + ".zip" # Rename the module folder to contain the version info. @@ -95,7 +90,7 @@ function PublishModulesAndChecksum else { Write-Host "Copying modules to pullserver module repository skipped because the machine is not a server sku or Pull server endpoint is not deployed." -Fore Yellow - } + } } From fbc4252eac4fb334efebfcdee32f7df3a1464e6b Mon Sep 17 00:00:00 2001 From: Ray Hayes Date: Mon, 14 Mar 2016 15:45:05 -0700 Subject: [PATCH 24/34] Remove compliance server and fix db choice --- .../MSFT_xDSCWebService.Schema.mof | 1 - .../MSFT_xDSCWebService.psm1 | 142 ++++++------------ 2 files changed, 49 insertions(+), 94 deletions(-) diff --git a/DSCResources/MSFT_xDSCWebService/MSFT_xDSCWebService.Schema.mof b/DSCResources/MSFT_xDSCWebService/MSFT_xDSCWebService.Schema.mof index c75dde570..b32eeb4b2 100644 --- a/DSCResources/MSFT_xDSCWebService/MSFT_xDSCWebService.Schema.mof +++ b/DSCResources/MSFT_xDSCWebService/MSFT_xDSCWebService.Schema.mof @@ -9,7 +9,6 @@ class MSFT_xDSCWebService : OMI_BaseResource [write,ValueMap{"Started","Stopped"},Values{"Started", "Stopped"}] string State; [write] string ModulePath; [write] string ConfigurationPath; - [write] boolean IsComplianceServer; [read] string DSCServerUrl; [write] string RegistrationKeyPath; [write] boolean AcceptSelfSignedCertificates; diff --git a/DSCResources/MSFT_xDSCWebService/MSFT_xDSCWebService.psm1 b/DSCResources/MSFT_xDSCWebService/MSFT_xDSCWebService.psm1 index a4c1d9b9c..78361c962 100644 --- a/DSCResources/MSFT_xDSCWebService/MSFT_xDSCWebService.psm1 +++ b/DSCResources/MSFT_xDSCWebService/MSFT_xDSCWebService.psm1 @@ -94,7 +94,7 @@ function Set-TargetResource [string]$EndpointName, # Port number of the DSC Pull Server IIS Endpoint - [Uint32]$Port = $( if ($IsComplianceServer) { 7070 } else { 8080 } ), + [Uint32]$Port = 8080, # Physical path for the IIS Endpoint on the machine (usually under inetpub) [string]$PhysicalPath = "$env:SystemDrive\inetpub\$EndpointName", @@ -116,14 +116,11 @@ function Set-TargetResource # Location on the disk where the Configuration is stored [string]$ConfigurationPath = "$env:PROGRAMFILES\WindowsPowerShell\DscService\Configuration", - # Is the endpoint for a DSC Compliance Server - [boolean]$IsComplianceServer, - # Location on the disk where the RegistrationKeys file is stored [string]$RegistrationKeyPath = "$env:PROGRAMFILES\WindowsPowerShell\DscService", # Add the IISSelfSignedCertModule native module to prevent self-signed certs being rejected. - [boolean]$AcceptSelfSignedCertificates + [boolean]$AcceptSelfSignedCertificates = $true ) # Initialize with default values @@ -150,41 +147,18 @@ function Set-TargetResource $IsBlue = $true; } + $isDownlevelOfBlue = $false; + if($os.Major -eq 6 -and $os.Minor -lt 3) + { + $isDownlevelOfBlue= $true; + } + # Use Pull Server values for defaults $webConfigFileName = "$pathPullServer\PSDSCPullServer.config" $svcFileName = "$pathPullServer\PSDSCPullServer.svc" $pswsMofFileName = "$pathPullServer\PSDSCPullServer.mof" $pswsDispatchFileName = "$pathPullServer\PSDSCPullServer.xml" - # Update only if Compliance Server install is requested - if ($IsComplianceServer) - { - $webConfigFileName = "$pathPullServer\PSDSCComplianceServer.config" - $svcFileName = "$pathPullServer\PSDSCComplianceServer.svc" - $pswsMofFileName = "$pathPullServer\PSDSCComplianceServer.mof" - $pswsDispatchFileName = "$pathPullServer\PSDSCComplianceServer.xml" - } - - # check for the existance of Windows authentication, this is needed for the Compliance Server - if(($Ensure -eq "Present")) - { - Write-Verbose "Check IIS Windows Authentication" - # only important if Present, Get-WindowsFeature works under 2008 R2 and newer - if ((Get-WindowsFeature -name Web-Windows-Auth | Where Installed).count -eq 0) - { - # enable the feature - # Checking for Windows Server 2008 R2: - if([Environment]::OSVersion.Version.ToString().StartsWith("6.1.")) - { - Add-WindowsFeature -Name Web-Windows-Auth - } - else - { - Install-WindowsFeature -Name Web-Windows-Auth - } - } - } - # ============ Absent block to remove existing site ========= if(($Ensure -eq "Absent")) { @@ -200,7 +174,6 @@ function Set-TargetResource return } # =========================================================== - Write-Verbose "Create the IIS endpoint" PSWSIISEndpoint\New-PSWSEndpoint -site $EndpointName ` @@ -223,68 +196,67 @@ function Set-TargetResource Update-LocationTagInApplicationHostConfigForAuthentication -WebSite $EndpointName -Authentication "basic" Update-LocationTagInApplicationHostConfigForAuthentication -WebSite $EndpointName -Authentication "windows" - if ($IsBlue) { Write-Verbose "Set values into the web.config that define the repository for BLUE OS" - #PSWSIISEndpoint\Set-AppSettingsInWebconfig -path $PhysicalPath -key "dbprovider" -value $eseprovider - #PSWSIISEndpoint\Set-AppSettingsInWebconfig -path $PhysicalPath -key "dbconnectionstr"-value $esedatabase - #ESE database is not present in current build PSWSIISEndpoint\Set-AppSettingsInWebconfig -path $PhysicalPath -key "dbprovider" -value $jet4provider PSWSIISEndpoint\Set-AppSettingsInWebconfig -path $PhysicalPath -key "dbconnectionstr" -value $jet4database Set-BindingRedirectSettingInWebConfig -path $PhysicalPath } else { - Write-Verbose "Set values into the web.config that define the repository for non-BLUE Downlevel OS" - $repository = Join-Path "$rootDataPath" "Devices.mdb" - Copy-Item "$pathPullServer\Devices.mdb" $repository -Force + if($isDownlevelOfBlue) + { + Write-Verbose "Set values into the web.config that define the repository for non-BLUE Downlevel OS" + $repository = Join-Path "$rootDataPath" "Devices.mdb" + Copy-Item "$pathPullServer\Devices.mdb" $repository -Force - PSWSIISEndpoint\Set-AppSettingsInWebconfig -path $PhysicalPath -key "dbprovider" -value $jet4provider - PSWSIISEndpoint\Set-AppSettingsInWebconfig -path $PhysicalPath -key "dbconnectionstr" -value $jet4database - } + PSWSIISEndpoint\Set-AppSettingsInWebconfig -path $PhysicalPath -key "dbprovider" -value $jet4provider + PSWSIISEndpoint\Set-AppSettingsInWebconfig -path $PhysicalPath -key "dbconnectionstr" -value $jet4database + } + else + { + Write-Verbose "Set values into the web.config that define the repository later than BLUE OS" + Write-Verbose "Only ESENT is supported on Windows Server 2016" - if ($IsComplianceServer) - { - Write-Verbose "Compliance Server: Set values into the web.config that indicate this is the admin endpoint" - PSWSIISEndpoint\Set-AppSettingsInWebconfig -path $PhysicalPath -key "AdminEndPoint" -value "true" + PSWSIISEndpoint\Set-AppSettingsInWebconfig -path $PhysicalPath -key "dbprovider" -value $eseprovider + PSWSIISEndpoint\Set-AppSettingsInWebconfig -path $PhysicalPath -key "dbconnectionstr"-value $esedatabase + } } - else - { - Write-Verbose "Pull Server: Set values into the web.config that indicate the location of repository, configuration, modules" - # Create the application data directory calculated above - $null = New-Item -path $rootDataPath -itemType "directory" -Force - - $repository = Join-Path $rootDataPath "Devices.mdb" - Copy-Item "$pathPullServer\Devices.mdb" $repository -Force + Write-Verbose "Pull Server: Set values into the web.config that indicate the location of repository, configuration, modules" - $null = New-Item -path "$ConfigurationPath" -itemType "directory" -Force + # Create the application data directory calculated above + $null = New-Item -path $rootDataPath -itemType "directory" -Force - PSWSIISEndpoint\Set-AppSettingsInWebconfig -path $PhysicalPath -key "ConfigurationPath" -value $ConfigurationPath + $repository = Join-Path $rootDataPath "Devices.mdb" + Copy-Item "$pathPullServer\Devices.mdb" $repository -Force - $null = New-Item -path "$ModulePath" -itemType "directory" -Force + $null = New-Item -path "$ConfigurationPath" -itemType "directory" -Force - PSWSIISEndpoint\Set-AppSettingsInWebconfig -path $PhysicalPath -key "ModulePath" -value $ModulePath + PSWSIISEndpoint\Set-AppSettingsInWebconfig -path $PhysicalPath -key "ConfigurationPath" -value $ConfigurationPath - $null = New-Item -path "$RegistrationKeyPath" -itemType "directory" -Force + $null = New-Item -path "$ModulePath" -itemType "directory" -Force - PSWSIISEndpoint\Set-AppSettingsInWebconfig -path $PhysicalPath -key "RegistrationKeyPath" -value $RegistrationKeyPath + PSWSIISEndpoint\Set-AppSettingsInWebconfig -path $PhysicalPath -key "ModulePath" -value $ModulePath - if($AcceptSelfSignedCertificates) - { - Copy-Item "$pathPullServer\IISSelfSignedCertModule.dll" $env:windir\System32\inetsrv -Force - Copy-Item "$env:windir\SysWOW64\WindowsPowerShell\v1.0\Modules\PSDesiredStateConfiguration\PullServer\IISSelfSignedCertModule.dll" $env:windir\SysWOW64\inetsrv -Force + $null = New-Item -path "$RegistrationKeyPath" -itemType "directory" -Force - & $script:appCmd install module /name:"IISSelfSignedCertModule(32bit)" /image:$env:windir\SysWOW64\inetsrv\IISSelfSignedCertModule.dll /add:false /lock:false - & $script:appCmd add module /name:"IISSelfSignedCertModule(32bit)" /app.name:"PSDSCPullServer/" - } - else + PSWSIISEndpoint\Set-AppSettingsInWebconfig -path $PhysicalPath -key "RegistrationKeyPath" -value $RegistrationKeyPath + + if($AcceptSelfSignedCertificates) + { + Copy-Item "$pathPullServer\IISSelfSignedCertModule.dll" $env:windir\System32\inetsrv -Force + Copy-Item "$env:windir\SysWOW64\WindowsPowerShell\v1.0\Modules\PSDesiredStateConfiguration\PullServer\IISSelfSignedCertModule.dll" $env:windir\SysWOW64\inetsrv -Force + + & $script:appCmd install module /name:"IISSelfSignedCertModule(32bit)" /image:$env:windir\SysWOW64\inetsrv\IISSelfSignedCertModule.dll /add:false /lock:false + & $script:appCmd add module /name:"IISSelfSignedCertModule(32bit)" /app.name:"PSDSCPullServer/" + } + else + { + if($AcceptSelfSignedCertificates -and ($AcceptSelfSignedCertificates -eq $false)) { - if($AcceptSelfSignedCertificates -and ($AcceptSelfSignedCertificates -eq $false)) - { - & $script:appCmd delete module /name:"IISSelfSignedCertModule(32bit)" /app.name:"PSDSCPullServer/" - } + & $script:appCmd delete module /name:"IISSelfSignedCertModule(32bit)" /app.name:"PSDSCPullServer/" } } } @@ -301,7 +273,7 @@ function Test-TargetResource [string]$EndpointName, # Port number of the DSC Pull Server IIS Endpoint - [Uint32]$Port = $( if ($IsComplianceServer) { 7070 } else { 8080 } ), + [Uint32]$Port = 8080, # Physical path for the IIS Endpoint on the machine (usually under inetpub) [string]$PhysicalPath = "$env:SystemDrive\inetpub\$EndpointName", @@ -323,13 +295,10 @@ function Test-TargetResource # Location on the disk where the Configuration is stored [string]$ConfigurationPath = "$env:PROGRAMFILES\WindowsPowerShell\DscService\Configuration", - # Is the endpoint for a DSC Compliance Server - [boolean]$IsComplianceServer, - # Location on the disk where the RegistrationKeys file is stored [string]$RegistrationKeyPath, - # Are self-signed certs being accepted for client auth. + # Are self-signed certs being accepted for client auth. [boolean]$AcceptSelfSignedCertificates ) @@ -361,19 +330,6 @@ function Test-TargetResource } # the other case is: Ensure and exist, we continue with more checks - # check for the existance of Windows authentication, this is needed for the Compliance Server - if(($Ensure -eq "Present")) - { - Write-Verbose "Check IIS Windows Authentication" - # only important if Present, Get-WindowsFeature works under 2008 R2 and newer - if ((Get-WindowsFeature -name Web-Windows-Auth | Where Installed).count -eq 0) - { - $DesiredConfigurationMatch = $false - Write-Verbose "Required Windows authentication is not installed, does not match the desired state." - break - } - } - Write-Verbose "Check Port" $actualPort = $website.bindings.Collection[0].bindingInformation.Split(":")[1] if ($Port -ne $actualPort) From b345fe9a8974e94aafd4b0f6d95de43f229ac183 Mon Sep 17 00:00:00 2001 From: Narine Mossikyan Date: Wed, 16 Mar 2016 10:50:22 -0700 Subject: [PATCH 25/34] Cmdlet to publish DSC modules and configuration documents on pull web server endpoint --- .../PublishModulesAndMofsToPullServer.psd1 | 80 ++++++++++++++++++ .../PublishModulesAndMofsToPullServer.psm1 | 56 ++++++++---- .../README.md | Bin 3 files changed, 119 insertions(+), 17 deletions(-) create mode 100644 DSCPullServerSetup/PublishModulesAndMofsToPullServer.psd1 rename DSCPullServer/PublishModulesAndMofsToPullServer.ps1 => DSCPullServerSetup/PublishModulesAndMofsToPullServer.psm1 (76%) rename {DSCPullServer => DSCPullServerSetup}/README.md (100%) diff --git a/DSCPullServerSetup/PublishModulesAndMofsToPullServer.psd1 b/DSCPullServerSetup/PublishModulesAndMofsToPullServer.psd1 new file mode 100644 index 000000000..6442f13f5 --- /dev/null +++ b/DSCPullServerSetup/PublishModulesAndMofsToPullServer.psd1 @@ -0,0 +1,80 @@ +# +# Module manifest for module 'PublishModulesAndMofsToPullServer' +# +# Generated by: Narine Mossikyan +# +# Generated on: 3/10/2016 +# +@{ +# Version number of this module. +ModuleVersion = '1.0' + +# ID used to uniquely identify this module +GUID = 'e4685473-cdc7-4396-bfbf-eab80e6f029d' + +# Author of this module +Author = 'Narine Mossikyan' + +# Company or vendor of this module +CompanyName = 'Microsoft Corporation' + +# Copyright statement for this module +Copyright = '(c) 2014 Microsoft Corporation. All rights reserved.' + +# Description of the functionality provided by this module +Description = 'PublishModulesAndMofsToPullServer module is a part of the Windows PowerShell Desired State Configuration (DSC) Resource Kit, which is a collection of DSC Resources produced by the PowerShell Team. This module contains helpers to package configuration documents and DSC modules from local path or Powershell module path and publish them on the DSC pull server endpoint.' + +# Minimum version of the Windows PowerShell engine required by this module +#PowerShellVersion = '' + +# Minimum version of the common language runtime (CLR) required by this module +#CLRVersion = '' + +# Functions to export from this module +FunctionsToExport = 'Publish-DSCModulesAndMofs' + +# Cmdlets to export from this module +CmdletsToExport = '*' + +# Variables to export from this module +VariablesToExport = '*' + +# Aliases to export from this module +AliasesToExport = '*' + +# DSC resources to export from this module +# DscResourcesToExport = @() + +# List of all modules packaged with this module +# ModuleList = @() + +# List of all files packaged with this module +# FileList = @() + +# Private data to pass to the module specified in RootModule/ModuleToProcess. This may also contain a PSData hashtable with additional module metadata used by PowerShell. +PrivateData = @{ + + PSData = @{ + + # Tags applied to this module. These help with module discovery in online galleries. + Tags = @('DSC pullserver module packaging', 'DSC', 'PullServer', 'DSCPullServer') + + # A URL to the license for this module. + LicenseUri = 'https://github.com/PowerShell/xPSDesiredStateConfiguration/blob/master/LICENSE' + + # A URL to the main website for this project. + ProjectUri = 'https://github.com/PowerShell/xPSDesiredStateConfiguration/DSCPullServerSetup' + + # A URL to an icon representing this module. + # IconUri = '' + + # ReleaseNotes of this module + ReleaseNotes = 'https://github.com/PowerShell/xPSDesiredStateConfiguration/DSCPullServerSetup/README.md' + + + } # End of PSData hashtable + +} # End of PrivateData hashtable +} + + diff --git a/DSCPullServer/PublishModulesAndMofsToPullServer.ps1 b/DSCPullServerSetup/PublishModulesAndMofsToPullServer.psm1 similarity index 76% rename from DSCPullServer/PublishModulesAndMofsToPullServer.ps1 rename to DSCPullServerSetup/PublishModulesAndMofsToPullServer.psm1 index 7cf83d403..25a46af6f 100644 --- a/DSCPullServer/PublishModulesAndMofsToPullServer.ps1 +++ b/DSCPullServerSetup/PublishModulesAndMofsToPullServer.psm1 @@ -1,11 +1,31 @@ +<# +.Synopsis + Package DSC modules and mof configuration document and publish them on enterprise DSC pull server in the required format +.DESCRIPTIO + Uses Publish-DSCModulesAndMofs cmdlet to package DSC modules into zip files with the version info. If + Publishes the zip modules on "$env:ProgramFiles\WindowsPowerShell\DscService\Modules" + Publishes all mof configuration documents that present in $Source folder on "$env:ProgramFiles\WindowsPowerShell\DscService\Configuration" + Use $Force to overwrite the version of the module that exists in powershell module path with the version from $source folder + Use $ModuleNameList to specify the names of the modules to be published if the modules do not exist in $Source folder + +.EXAMPLE + $moduleList = @("xWebAdministration", "xPhp") + Publish-DSCModulesAndMofs -Source C:\LocalDepot -ModuleNameList $moduleList +.EXAMPLE + Publish-DSCModulesAndMofs -Source C:\LocalDepot -Force + +#> + # A tool to use to package DSC modules and mof configuration document and publish them on enterprise DSC pull server in the required format +function Publish-DSCModulesAndMofs +{ param( [Parameter(Mandatory=$True)] [string]$Source = $pwd, # The folder that contains the configuration mof documents and modules to be published on pull server. Everything in this folder will be packaged and published. -[switch]$Force, #switch to overwrite the module if $Source is provided and a different version of the module presents in powershell module path -[string[]]$ModuleNameList # optional parameter to package modules listed in $ListModuleNames based on powershell module path content +[switch]$Force, #switch to overwrite the module in PSModulePath with the version provided in $Sources +[string[]]$ModuleNameList # Package and publish the modules listed in $ModuleNameList based on powershell module path content ) @@ -16,6 +36,21 @@ New-Item -Path $tempFolder -ItemType Directory -Force -ErrorAction SilentlyConti #Copy the mof documents from the $Source to working dir Copy-Item -Path "$Source\*.mof" -Destination $tempFolder -Force -Verbose +#Start Deployment! +Write-Host "Start deployment" +CreateZipFromPSModulePath -listModuleNames $ModuleNameList -destination $tempFolder +CreateZipFromSource -source $Source -destination $tempFolder +# Generate the checkSum file for all the zip and mof files. +New-DSCCheckSum $tempFolder -Force +# Publish mof and modules to pull server repositories +PublishModulesAndChecksum -source $tempFolder +PublishMofDocuments -source $tempFolder +#Deployment is complete! +Remove-Item -Path $tempFolder -Recurse -Force -ErrorAction SilentlyContinue +Write-Host "End deployment" + +} + #Package the modules using powershell module path function CreateZipFromPSModulePath { @@ -68,7 +103,7 @@ function CreateZipFromSource } else { - Write-Host "Skipping module overwrite. Module with the name $name already exists. Please specify -Force to overwrite the module with the version located in $source or remove the module folder from $source." + Write-Host "Skipping module overwrite. Module with the name $name already exists. Please specify -Force to overwrite the module with the local version of the module located in $source or list names of the modules in ModuleNameList parameter to be packaged from powershell module pat instead and remove them from $source folder" -Fore Red } $modules+= @("$name") } @@ -108,17 +143,4 @@ function PublishMofDocuments { Write-Host "Copying configuration(s) to pullserver configuration repository skipped because the machine is not a server sku or Pull server endpoint is not deployed." -Fore Yellow } -} - -#Start Deployment! -Write-Host "Start deployment" -CreateZipFromPSModulePath -listModuleNames $ModuleNameList -destination $tempFolder -CreateZipFromSource -source $Source -destination $tempFolder -# Generate the checkSum file for all the zip and mof files. -New-DSCCheckSum $tempFolder -Force -# Publish mof and modules to pull server repositories -PublishModulesAndChecksum -source $tempFolder -PublishMofDocuments -source $tempFolder -#Deployment is complete! -Remove-Item -Path $tempFolder -Recurse -Force -ErrorAction SilentlyContinue -Write-Host "End deployment" \ No newline at end of file +} \ No newline at end of file diff --git a/DSCPullServer/README.md b/DSCPullServerSetup/README.md similarity index 100% rename from DSCPullServer/README.md rename to DSCPullServerSetup/README.md From bde4b0b0fc68a99be3f0b41cb734bd634eb28e66 Mon Sep 17 00:00:00 2001 From: Narine Mossikyan Date: Wed, 16 Mar 2016 13:28:19 -0700 Subject: [PATCH 26/34] Cmdlet to publish dsc module and configuration documents on dsc enterprise pull server --- DSCPullServerSetup/PublishModulesAndMofsToPullServer.psm1 | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/DSCPullServerSetup/PublishModulesAndMofsToPullServer.psm1 b/DSCPullServerSetup/PublishModulesAndMofsToPullServer.psm1 index 25a46af6f..6a4ffb14e 100644 --- a/DSCPullServerSetup/PublishModulesAndMofsToPullServer.psm1 +++ b/DSCPullServerSetup/PublishModulesAndMofsToPullServer.psm1 @@ -1,7 +1,7 @@ <# .Synopsis Package DSC modules and mof configuration document and publish them on enterprise DSC pull server in the required format -.DESCRIPTIO +.DESCRIPTION Uses Publish-DSCModulesAndMofs cmdlet to package DSC modules into zip files with the version info. If Publishes the zip modules on "$env:ProgramFiles\WindowsPowerShell\DscService\Modules" Publishes all mof configuration documents that present in $Source folder on "$env:ProgramFiles\WindowsPowerShell\DscService\Configuration" @@ -16,7 +16,7 @@ #> -# A tool to use to package DSC modules and mof configuration document and publish them on enterprise DSC pull server in the required format +# Tools to use to package DSC modules and mof configuration document and publish them on enterprise DSC pull server in the required format function Publish-DSCModulesAndMofs { @@ -143,4 +143,4 @@ function PublishMofDocuments { Write-Host "Copying configuration(s) to pullserver configuration repository skipped because the machine is not a server sku or Pull server endpoint is not deployed." -Fore Yellow } -} \ No newline at end of file +} From 3e82c17282181ee42d9db4dcfc3f9358007b5610 Mon Sep 17 00:00:00 2001 From: Narine Mossikyan Date: Wed, 16 Mar 2016 14:28:53 -0700 Subject: [PATCH 27/34] Updated to address review comments - Cmdlet to publish dsc module and configuration documents on dsc enterprise pull server --- .../PublishModulesAndMofsToPullServer.psd1 | 80 ------------------- 1 file changed, 80 deletions(-) delete mode 100644 DSCPullServerSetup/PublishModulesAndMofsToPullServer.psd1 diff --git a/DSCPullServerSetup/PublishModulesAndMofsToPullServer.psd1 b/DSCPullServerSetup/PublishModulesAndMofsToPullServer.psd1 deleted file mode 100644 index 6442f13f5..000000000 --- a/DSCPullServerSetup/PublishModulesAndMofsToPullServer.psd1 +++ /dev/null @@ -1,80 +0,0 @@ -# -# Module manifest for module 'PublishModulesAndMofsToPullServer' -# -# Generated by: Narine Mossikyan -# -# Generated on: 3/10/2016 -# -@{ -# Version number of this module. -ModuleVersion = '1.0' - -# ID used to uniquely identify this module -GUID = 'e4685473-cdc7-4396-bfbf-eab80e6f029d' - -# Author of this module -Author = 'Narine Mossikyan' - -# Company or vendor of this module -CompanyName = 'Microsoft Corporation' - -# Copyright statement for this module -Copyright = '(c) 2014 Microsoft Corporation. All rights reserved.' - -# Description of the functionality provided by this module -Description = 'PublishModulesAndMofsToPullServer module is a part of the Windows PowerShell Desired State Configuration (DSC) Resource Kit, which is a collection of DSC Resources produced by the PowerShell Team. This module contains helpers to package configuration documents and DSC modules from local path or Powershell module path and publish them on the DSC pull server endpoint.' - -# Minimum version of the Windows PowerShell engine required by this module -#PowerShellVersion = '' - -# Minimum version of the common language runtime (CLR) required by this module -#CLRVersion = '' - -# Functions to export from this module -FunctionsToExport = 'Publish-DSCModulesAndMofs' - -# Cmdlets to export from this module -CmdletsToExport = '*' - -# Variables to export from this module -VariablesToExport = '*' - -# Aliases to export from this module -AliasesToExport = '*' - -# DSC resources to export from this module -# DscResourcesToExport = @() - -# List of all modules packaged with this module -# ModuleList = @() - -# List of all files packaged with this module -# FileList = @() - -# Private data to pass to the module specified in RootModule/ModuleToProcess. This may also contain a PSData hashtable with additional module metadata used by PowerShell. -PrivateData = @{ - - PSData = @{ - - # Tags applied to this module. These help with module discovery in online galleries. - Tags = @('DSC pullserver module packaging', 'DSC', 'PullServer', 'DSCPullServer') - - # A URL to the license for this module. - LicenseUri = 'https://github.com/PowerShell/xPSDesiredStateConfiguration/blob/master/LICENSE' - - # A URL to the main website for this project. - ProjectUri = 'https://github.com/PowerShell/xPSDesiredStateConfiguration/DSCPullServerSetup' - - # A URL to an icon representing this module. - # IconUri = '' - - # ReleaseNotes of this module - ReleaseNotes = 'https://github.com/PowerShell/xPSDesiredStateConfiguration/DSCPullServerSetup/README.md' - - - } # End of PSData hashtable - -} # End of PrivateData hashtable -} - - From 60d427078c6007cfbc6aa56dd7479f40ab6ca2f6 Mon Sep 17 00:00:00 2001 From: Narine Mossikyan Date: Wed, 16 Mar 2016 17:06:55 -0700 Subject: [PATCH 28/34] Removed psd1 from DSCPullServerSetup. Made Publish-DSCModuleAndMof to be part of xPSDesiredStateConfiguration module --- DSCPullServerSetup/PublishModulesAndMofsToPullServer.psm1 | 3 ++- xPSDesiredStateConfiguration.psd1 | 3 +++ 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/DSCPullServerSetup/PublishModulesAndMofsToPullServer.psm1 b/DSCPullServerSetup/PublishModulesAndMofsToPullServer.psm1 index 6a4ffb14e..96a09492b 100644 --- a/DSCPullServerSetup/PublishModulesAndMofsToPullServer.psm1 +++ b/DSCPullServerSetup/PublishModulesAndMofsToPullServer.psm1 @@ -18,7 +18,7 @@ # Tools to use to package DSC modules and mof configuration document and publish them on enterprise DSC pull server in the required format -function Publish-DSCModulesAndMofs +function Publish-DSCModuleAndMof { param( @@ -144,3 +144,4 @@ function PublishMofDocuments Write-Host "Copying configuration(s) to pullserver configuration repository skipped because the machine is not a server sku or Pull server endpoint is not deployed." -Fore Yellow } } +Export-ModuleMember -Function Publish-DSCModuleAndMof \ No newline at end of file diff --git a/xPSDesiredStateConfiguration.psd1 b/xPSDesiredStateConfiguration.psd1 index 0d54b1279..29ce736d7 100644 --- a/xPSDesiredStateConfiguration.psd1 +++ b/xPSDesiredStateConfiguration.psd1 @@ -31,6 +31,9 @@ FunctionsToExport = '*' # Cmdlets to export from this module CmdletsToExport = '*' +#Root module +RootModule = 'DSCPullServerSetup\PublishModulesAndMofsToPullServer.psm1' + # Private data to pass to the module specified in RootModule/ModuleToProcess. This may also contain a PSData hashtable with additional module metadata used by PowerShell. PrivateData = @{ From f549d3175474ed51d73dba4a36574385ab80a750 Mon Sep 17 00:00:00 2001 From: Narine Mossikyan Date: Fri, 18 Mar 2016 11:09:10 -0700 Subject: [PATCH 29/34] added new line to psm1 --- DSCPullServerSetup/PublishModulesAndMofsToPullServer.psm1 | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/DSCPullServerSetup/PublishModulesAndMofsToPullServer.psm1 b/DSCPullServerSetup/PublishModulesAndMofsToPullServer.psm1 index 96a09492b..04829c6da 100644 --- a/DSCPullServerSetup/PublishModulesAndMofsToPullServer.psm1 +++ b/DSCPullServerSetup/PublishModulesAndMofsToPullServer.psm1 @@ -144,4 +144,4 @@ function PublishMofDocuments Write-Host "Copying configuration(s) to pullserver configuration repository skipped because the machine is not a server sku or Pull server endpoint is not deployed." -Fore Yellow } } -Export-ModuleMember -Function Publish-DSCModuleAndMof \ No newline at end of file +Export-ModuleMember -Function Publish-DSCModuleAndMof From 9ae7849af31c53ffd1f381e440484b61cd3fd318 Mon Sep 17 00:00:00 2001 From: Narine Mossikyan Date: Fri, 18 Mar 2016 12:21:10 -0700 Subject: [PATCH 30/34] fixed the typo in the name of cmdlet in the examples --- DSCPullServerSetup/PublishModulesAndMofsToPullServer.psm1 | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/DSCPullServerSetup/PublishModulesAndMofsToPullServer.psm1 b/DSCPullServerSetup/PublishModulesAndMofsToPullServer.psm1 index 04829c6da..5116f3a58 100644 --- a/DSCPullServerSetup/PublishModulesAndMofsToPullServer.psm1 +++ b/DSCPullServerSetup/PublishModulesAndMofsToPullServer.psm1 @@ -10,9 +10,9 @@ .EXAMPLE $moduleList = @("xWebAdministration", "xPhp") - Publish-DSCModulesAndMofs -Source C:\LocalDepot -ModuleNameList $moduleList + Publish-DSCModuleAndMof -Source C:\LocalDepot -ModuleNameList $moduleList .EXAMPLE - Publish-DSCModulesAndMofs -Source C:\LocalDepot -Force + Publish-DSCModuleAndMof -Source C:\LocalDepot -Force #> From 1d22fb9eeff93c53b07b193ddae514bec939f7ee Mon Sep 17 00:00:00 2001 From: Ray Hayes Date: Fri, 18 Mar 2016 14:56:48 -0700 Subject: [PATCH 31/34] esent fixes --- DSCResources/MSFT_xDSCWebService/MSFT_xDSCWebService.psm1 | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/DSCResources/MSFT_xDSCWebService/MSFT_xDSCWebService.psm1 b/DSCResources/MSFT_xDSCWebService/MSFT_xDSCWebService.psm1 index 78361c962..f0471566d 100644 --- a/DSCResources/MSFT_xDSCWebService/MSFT_xDSCWebService.psm1 +++ b/DSCResources/MSFT_xDSCWebService/MSFT_xDSCWebService.psm1 @@ -199,8 +199,8 @@ function Set-TargetResource if ($IsBlue) { Write-Verbose "Set values into the web.config that define the repository for BLUE OS" - PSWSIISEndpoint\Set-AppSettingsInWebconfig -path $PhysicalPath -key "dbprovider" -value $jet4provider - PSWSIISEndpoint\Set-AppSettingsInWebconfig -path $PhysicalPath -key "dbconnectionstr" -value $jet4database + PSWSIISEndpoint\Set-AppSettingsInWebconfig -path $PhysicalPath -key "dbprovider" -value $eseprovider + PSWSIISEndpoint\Set-AppSettingsInWebconfig -path $PhysicalPath -key "dbconnectionstr"-value $esedatabase Set-BindingRedirectSettingInWebConfig -path $PhysicalPath } else From 034e760957bd71937131533a7863607089ff619e Mon Sep 17 00:00:00 2001 From: NarineM Date: Fri, 18 Mar 2016 17:13:56 -0700 Subject: [PATCH 32/34] Update README.md --- README.md | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index 20480b73f..558294aa8 100644 --- a/README.md +++ b/README.md @@ -165,6 +165,8 @@ Note: _the xWindowsOptionalFeature is only supported on Windows client or Window ### Unreleased * Added Pester tests to validate pullserver deployement. +* Removed Compliance Server deployment from xWebservice resource. Fixed database provider selection issue depending on OS flavor +* Added Publish-DSCModuleAndMof cmdlet to package DSC modules and mof and publish them on DSC enterprise pull server ### 3.7.0.0 @@ -298,4 +300,4 @@ This configuration will install a .exe package and verify the package using the ### Pester tests to validate pullserver deployement. -[Pullserver Validation Tests](Examples/PullServerDeploymentVerificationTest) \ No newline at end of file +[Pullserver Validation Tests](Examples/PullServerDeploymentVerificationTest) From a859f10f0eaea1200953f4147051266dc8fb5879 Mon Sep 17 00:00:00 2001 From: KarolKaczmarek Date: Fri, 18 Mar 2016 17:17:16 -0700 Subject: [PATCH 33/34] Update README.md --- README.md | 1 + 1 file changed, 1 insertion(+) diff --git a/README.md b/README.md index 558294aa8..b0b269b7a 100644 --- a/README.md +++ b/README.md @@ -167,6 +167,7 @@ Note: _the xWindowsOptionalFeature is only supported on Windows client or Window * Added Pester tests to validate pullserver deployement. * Removed Compliance Server deployment from xWebservice resource. Fixed database provider selection issue depending on OS flavor * Added Publish-DSCModuleAndMof cmdlet to package DSC modules and mof and publish them on DSC enterprise pull server +* xRemoteFile resource: Added size verification in cache ### 3.7.0.0 From ae79c8919895e96986850428dde93ef3396f82dd Mon Sep 17 00:00:00 2001 From: Karol Kaczmarek Date: Fri, 18 Mar 2016 17:21:05 -0700 Subject: [PATCH 34/34] Releasing version 3.8.0.0 --- README.md | 2 ++ appveyor.yml | 4 ++-- xPSDesiredStateConfiguration.psd1 | 2 +- 3 files changed, 5 insertions(+), 3 deletions(-) diff --git a/README.md b/README.md index b0b269b7a..82f45e191 100644 --- a/README.md +++ b/README.md @@ -164,6 +164,8 @@ Note: _the xWindowsOptionalFeature is only supported on Windows client or Window ### Unreleased +### 3.8.0.0 + * Added Pester tests to validate pullserver deployement. * Removed Compliance Server deployment from xWebservice resource. Fixed database provider selection issue depending on OS flavor * Added Publish-DSCModuleAndMof cmdlet to package DSC modules and mof and publish them on DSC enterprise pull server diff --git a/appveyor.yml b/appveyor.yml index d9b67ed71..72eeb2bdb 100644 --- a/appveyor.yml +++ b/appveyor.yml @@ -1,7 +1,7 @@ #---------------------------------# # environment configuration # #---------------------------------# -version: 3.7.{build}.0 +version: 3.8.{build}.0 install: - cinst -y pester - git clone https://github.com/PowerShell/DscResource.Tests @@ -41,7 +41,7 @@ deploy_script: # Creating project artifact $stagingDirectory = (Resolve-Path ..).Path $manifest = Join-Path $pwd "xPSDesiredStateConfiguration.psd1" - (Get-Content $manifest -Raw).Replace("3.7.0.0", $env:APPVEYOR_BUILD_VERSION) | Out-File $manifest + (Get-Content $manifest -Raw).Replace("3.8.0.0", $env:APPVEYOR_BUILD_VERSION) | Out-File $manifest $zipFilePath = Join-Path $stagingDirectory "$(Split-Path $pwd -Leaf).zip" Add-Type -assemblyname System.IO.Compression.FileSystem [System.IO.Compression.ZipFile]::CreateFromDirectory($pwd, $zipFilePath) diff --git a/xPSDesiredStateConfiguration.psd1 b/xPSDesiredStateConfiguration.psd1 index 29ce736d7..ead62b5bf 100644 --- a/xPSDesiredStateConfiguration.psd1 +++ b/xPSDesiredStateConfiguration.psd1 @@ -1,6 +1,6 @@ @{ # Version number of this module. -ModuleVersion = '3.7.0.0' +ModuleVersion = '3.8.0.0' # ID used to uniquely identify this module GUID = 'cc8dc021-fa5f-4f96-8ecf-dfd68a6d9d48'