DSCResources/NetscapeBookmarkLink/NetscapeBookmarkLink.psm1
Enum Ensure { Present Absent } # Import helper functions $UtilPath = Join-Path -Path (Split-Path -Path (Split-Path -Path $PSScriptRoot -Parent) -Parent) -ChildPath 'Utils' # Import-Module (Join-Path $UtilPath 'ConvertTo-HashTable.psm1') Import-Module (Join-Path $UtilPath 'Validate-DateTime.psm1') -DisableNameChecking # Import parser libraries $LibPath = Join-Path -Path (Split-Path -Path (Split-Path -Path $PSScriptRoot -Parent) -Parent) -ChildPath 'Libs' if (-not ('BookmarksManager.NetscapeBookmarksReader' -as [type])) { Add-Type -Path (Join-Path $LibPath '\BookmarksManager\netstandard1.6\BookmarksManager.dll') } function Get-TargetResource { [CmdletBinding()] [OutputType([System.Collections.Hashtable])] param ( # The path to the bookmark file [Parameter(Mandatory = $true)] [System.String] $Path, # The title of the bookmark folder that the target link should be belonging to [Parameter(Mandatory = $true)] [System.String] $Folder, # The title of the target link [Parameter(Mandatory = $true)] [System.String] $Title, # The URL of the link [Parameter(Mandatory = $true)] [System.String] $Url ) $GetObject = @{ Ensure = [Ensure]::Present Path = $Path Folder = '' Title = '' } # Test if the bookmarks file exists if ([string]::IsNullOrWhiteSpace($Path) -or (-not (Test-Path -LiteralPath $Path -PathType Leaf))) { $GetObject.Ensure = [Ensure]::Absent return $GetObject } # Read and parse the bookmark file $BookmarkContent = Get-Content -LiteralPath $Path -Raw -Encoding utf8 $Reader = [BookmarksManager.NetscapeBookmarksReader]::new() try { $Bookmark = $Reader.Read($BookmarkContent) } catch { # Failed to parse the bookmark file Write-Verbose -Message 'Failed to parse the bookmark file' $GetObject.Ensure = [Ensure]::Absent return $GetObject } # Test if the folder exists in the bookmark file $TargetFolder = $Bookmark.AllFolders | ? { $_.Title -eq $Folder } | select -First 1 if ($null -eq $TargetFolder) { # Folder does not exist $GetObject.Ensure = [Ensure]::Absent return $GetObject } else { $GetObject.Folder = $TargetFolder.Title } # Test if the link exists in the folder $TargetItem = $TargetFolder.AllLinks | ? { $_.Title -eq $Title } | select -First 1 if ($null -eq $TargetItem) { # Link does not exist $GetObject.Ensure = [Ensure]::Absent return $GetObject } else { # Link exists $GetObject.Ensure = [Ensure]::Present $GetObject.Title = $TargetItem.Title } # URL $GetObject.Url = $TargetItem.Url # ADD_DATE $GetObject.AddDate = $TargetItem.Added # LAST_MODIFIED $GetObject.ModifiedDate = $TargetItem.LastModified # IconData $GetObject.IconData = $TargetItem.Attributes.'icon' # IconUrl $GetObject.IconUrl = $TargetItem.IconUrl return $GetObject } function Set-TargetResource { [CmdletBinding()] param ( [Parameter()] [System.String] $Ensure = [Ensure]::Present, # The path to the bookmark file [Parameter(Mandatory = $true)] [System.String] $Path, # The title of the bookmark folder that the target link should be belonging to [Parameter(Mandatory = $true)] [System.String] $Folder, # The title of the target link [Parameter(Mandatory = $true)] [System.String] $Title, # The URL of the link [Parameter(Mandatory = $true)] [System.String] $Url, # The ADD_DATE of the link [Parameter()] [Nullable[System.DateTime]] $AddDate, # The LAST_MODIFIED of the link [Parameter()] [Nullable[System.DateTime]] $ModifiedDate, # The Data URI of the icon [Parameter()] [System.String] $IconData, # The URL of the icon [Parameter()] [System.String] $IconUrl ) # Validate range of datetime $AddDate = if (Validate-DateTime $AddDate) { $AddDate }else { $null } $ModifiedDate = if (Validate-DateTime $ModifiedDate) { $ModifiedDate }else { $null } if ($Ensure -eq [Ensure]::Absent) { $GetObject = Get-TargetResource -Path $Path -Title $Title -Url $Url -Folder $Folder if ($GetObject.Ensure -eq [Ensure]::Absent) { Write-Verbose -Message 'Nothing to do.' return } else { # Read and parse the bookmark file $BookmarkContent = Get-Content -LiteralPath $Path -Raw -Encoding utf8 $Reader = [BookmarksManager.NetscapeBookmarksReader]::new() $Bookmark = $Reader.Read($BookmarkContent) # Remove the link $Bookmark.AllFolders | ? { $_.Title -eq $Folder } | % { $Target = $_.AllLinks | ? { $_.Title -eq $Title } | select -First 1 Write-Verbose -Message 'Removing link from folder.' $null = $_.Remove($Target) } # Save the bookmark file Write-Verbose -Message 'Saving bookmark file.' $Writer = [BookmarksManager.NetscapeBookmarksWriter]::new($Bookmark) $ParentFolder = Split-Path -Path $Path -Parent if (-not (Test-Path -LiteralPath $ParentFolder -PathType Container)) { $null = New-Item -ItemType Directory -Path $ParentFolder -Force } $Writer.ToString() | Out-File -FilePath $Path -Encoding utf8 -Force -NoNewline Write-Verbose -Message 'The bookmark file has been saved.' } } else { # if the bookmark file does not exist, create it if ([string]::IsNullOrWhiteSpace($Path) -or (-not (Test-Path -LiteralPath $Path -PathType Leaf))) { Write-Verbose -Message 'The bookmark file does not exist. Creating it...' $NewBookmarkParent = [BookmarksManager.BookmarkFolder]::new() } else { # Read and parse the bookmark file $BookmarkContent = Get-Content -LiteralPath $Path -Raw -Encoding utf8 $Reader = [BookmarksManager.NetscapeBookmarksReader]::new() $NewBookmarkParent = $Reader.Read($BookmarkContent) } # Get target folder $TargetFolder = $NewBookmarkParent.AllFolders | ? { $_.Title -eq $Folder } | select -First 1 if ($null -eq $TargetFolder) { # if that does not exist, create it Write-Verbose -Message 'The target folder does not exist. Creating it...' $TargetFolder = [BookmarksManager.BookmarkFolder]::new() $TargetFolder.Title = $Folder $NewBookmarkParent.Add($TargetFolder) } # Get target link $TargetLink = $TargetFolder.AllLinks | ? { $_.Title -eq $Title } | select -First 1 if ($null -eq $TargetLink) { # if that does not exist, create it Write-Verbose -Message 'The target link does not exist. Creating it...' $TargetLink = [BookmarksManager.BookmarkLink]::new($Url, $Title) $TargetFolder.Add($TargetLink) } # Set URL Write-Verbose -Message "Set the URL to $Url" $TargetLink.Url = $Url # Set ADD_DATE if ($null -ne $AddDate) { Write-Verbose -Message ('Set the ADD_DATE to {0}' -f $AddDate.ToString("yyyy-MM-dd'T'HH:mm:sszzz")) $TargetLink.Added = $AddDate.ToUniversalTime() } # Set LAST_MODIFIED if ($null -ne $ModifiedDate) { Write-Verbose -Message ('Set the LAST_MODIFIED to {0}' -f $ModifiedDate.ToString("yyyy-MM-dd'T'HH:mm:sszzz")) $TargetLink.LastModified = $ModifiedDate.ToUniversalTime() } # Set IconData if (-not [string]::IsNullOrEmpty($IconData)) { Write-Verbose -Message 'Set the IconData' $tmp = $IconData.Split([char[]](':', ';', ',')) $TargetLink.IconContentType = $tmp[1] $TargetLink.IconData = [System.Convert]::FromBase64String($tmp[3]) } # Set IconUrl if (-not [string]::IsNullOrEmpty($IconUrl)) { Write-Verbose -Message 'Set the IconUrl' $TargetLink.IconUrl = $IconUrl } # Save the bookmark file Write-Verbose -Message 'Saving the bookmark file...' $Writer = [BookmarksManager.NetscapeBookmarksWriter]::new($NewBookmarkParent) $ParentFolder = Split-Path -Path $Path -Parent if (-not (Test-Path -LiteralPath $ParentFolder -PathType Container)) { $null = New-Item -ItemType Directory -Path $ParentFolder -Force } $Writer.ToString() | Out-File -FilePath $Path -Encoding utf8 -Force -NoNewline Write-Verbose -Message 'The bookmark file has been saved.' } } function Test-TargetResource { [CmdletBinding()] [OutputType([System.Boolean])] param ( [Parameter()] [System.String] $Ensure = [Ensure]::Present, # The path to the bookmark file [Parameter(Mandatory = $true)] [System.String] $Path, # The title of the bookmark folder that the target link should be belonging to [Parameter(Mandatory = $true)] [System.String] $Folder, # The title of the target link [Parameter(Mandatory = $true)] [System.String] $Title, # The URL of the link [Parameter(Mandatory = $true)] [System.String] $Url, # The ADD_DATE of the link [Parameter()] [Nullable[System.DateTime]] $AddDate, # The LAST_MODIFIED of the link [Parameter()] [Nullable[System.DateTime]] $ModifiedDate, # The Data URI of the icon [Parameter()] [System.String] $IconData, # The URL of the icon [Parameter()] [System.String] $IconUrl ) # Validate range of datetime $AddDate = if (Validate-DateTime $AddDate) { $AddDate }else { $null } $ModifiedDate = if (Validate-DateTime $ModifiedDate) { $ModifiedDate }else { $null } # Get current state $CurrentState = Get-TargetResource -Path $Path -Title $Title -Url $Url -Folder $Folder # Test if the bookmarks file exists if ([string]::IsNullOrWhiteSpace($Path) -or (-not (Test-Path -LiteralPath $Path -PathType Leaf))) { return ($Ensure -eq [Ensure]::Absent) } # Read and parse the bookmark file try { $BookmarkContent = Get-Content -LiteralPath $Path -Raw -Encoding utf8 $Reader = [BookmarksManager.NetscapeBookmarksReader]::new() $null = $Reader.Read($BookmarkContent) } catch { # Failed to parse the bookmark file Write-Verbose -Message 'Failed to parse the bookmark file' return ($Ensure -eq [Ensure]::Absent) } finally { Remove-Variable -Name BookmarkContent Remove-Variable -Name Reader } if ($CurrentState.Ensure -ne $Ensure) { Write-Verbose -Message ('The target resource is not in the expected state. Expected {0}, but got {1}' -f $Ensure, $CurrentState.Ensure) return $false } # The title of the link is different, return False if ($Title -ne $CurrentState.Title) { Write-Verbose -Message ('The title of the link is not in the expected state. Expected {0}, but got {1}' -f $Title, $CurrentState.Title) return ($Ensure -eq [Ensure]::Absent) } # The URL of the link is different, return False if ($Url -ne $CurrentState.Url) { Write-Verbose -Message ('The URL of the link is not in the expected state. Expected {0}, but got {1}' -f $Url, $CurrentState.Url) return $false } if ($null -ne $AddDate) { # The ADD_DATE of the link is different, return False if (($CurrentState.AddDate -isnot [datetime]) -or ($AddDate.ToUniversalTime() -ne $CurrentState.AddDate.ToUniversalTime())) { Write-Verbose -Message ('The ADD_DATE attribute is not in the expected state. Expected {0}, but got {1}' -f $AddDate.ToUniversalTime().ToString("yyyy-MM-dd'T'HH:mm:sszzz"), $CurrentState.AddDate.ToUniversalTime().ToString("yyyy-MM-dd'T'HH:mm:sszzz")) return $false } } if ($null -ne $ModifiedDate) { # The LAST_MODIFIED of the link is different, return False if (($CurrentState.ModifiedDate -isnot [datetime]) -or ($ModifiedDate.ToUniversalTime() -ne $CurrentState.ModifiedDate.ToUniversalTime())) { Write-Verbose -Message ('The LAST_MODIFIED attribute is not in the expected state. Expected {0}, but got {1}' -f $ModifiedDate.ToUniversalTime().ToString("yyyy-MM-dd'T'HH:mm:sszzz"), $CurrentState.ModifiedDate.ToUniversalTime().ToString("yyyy-MM-dd'T'HH:mm:sszzz")) return $false } } if (-not [string]::IsNullOrEmpty($IconData)) { # The IconData of the link is different, return False if ($IconData -ne $CurrentState.IconData) { Write-Verbose -Message ('The IconData attribute is not in the expected state.') return $false } } if (-not [string]::IsNullOrEmpty($IconUrl)) { # The IconUrl of the link is different, return False if ($IconUrl -ne $CurrentState.IconUrl) { Write-Verbose -Message ('The IconUrl attribute is not in the expected state. Expected {0}, but got {1}' -f $IconUrl, $CurrentState.IconUrl) return $false } } Write-Verbose -Message 'The target resource is in the expected state.' return $true } Export-ModuleMember -Function *-TargetResource |