MetaNullUtils.psm1
# Module Constants # Registry Hive for the module Set-Variable CRegistryHive -option Constant -value ([string]"HKCU:\SOFTWARE\MetaNullUtils") # Time, in minutes, for how long cached data is considered valid Set-Variable CCredentialCacheDuration -option Constant -value ([int]43200) Function Get-HtmlDoctype { <# .SYNOPSIS Get the XML doctype for a HTML document .DESCRIPTION Get the XML doctype for a HTML document, including the lis tof HTML entities .Example Get-HtmlDoctype #> [CmdletBinding()] [OutputType([string[]])] param () Process { Write-Output '<!DOCTYPE xml [ ' Get-HtmlEntity | ForEach-Object { Write-Output "<!ENTITY $($_) """"> " } Write-Output ']>' } } Function Get-HtmlEntity { <# .SYNOPSIS Get a list of HTML entities .Example Get-HtmlEntity #> [CmdletBinding()] [OutputType([string[]])] param () Process { Write-Output @( 'aacute' 'Aacute' 'Acirc' 'acirc' 'Aelig' 'aelig' 'agrave' 'Agrave' 'aring' 'Aring' 'atilde' 'Atilde' 'auml' 'Auml' 'bdquo' 'brvbar' 'bull' 'ccedil' 'clubs' 'copy' 'darr' 'diams' 'eacute' 'Eacute' 'ecirc' 'Ecirc' 'egrave' 'Egrave' 'euml' 'Euml' 'hearts' 'hellip' 'iacute' 'Iacute' 'icirc' 'Icirc' 'igrave' 'Igrave' 'iuml' 'Iuml' 'laquo' 'larr' 'ldquo' 'lsaquo' 'lsquo' 'mbash' 'middot' 'nbsp' 'ndash' 'nearr' 'ntilde' 'Ntilde' 'nwarr' 'oacute' 'Oacute' 'ocirc' 'Ocirc' 'ograve' 'Ograve' 'otilde' 'Otilde' 'ouml' 'Ouml' 'quot' 'raquo' 'rarr' 'rdquo' 'rsaquo' 'rsquo' 'sbquo' 'searr' 'spades' 'swarr' 'szlig' 'trade' 'uacute' 'Uacute' 'uarr' 'Uarr' 'Ucirc' 'ucirc' 'ugrave' 'Ugrave' 'uuml' 'Uuml' ) } } Function Get-SecureStringByteArray { <# .SYNOPSIS Get bytes from a secure string to permit comparison .Description Get bytes from a secure string to permit comparison .PARAMETER SecureString A secure string .Example Get-SecureStringByteArray $Credential.Password #> [CmdletBinding()] [OutputType([PSCustomObject])] param ( [Parameter(Position=0,ValueFromPipeline)] [Security.SecureString]$SecureString ) Process { $BSTR = [Runtime.InteropServices.Marshal]::SecureStringToBSTR($SecureString) $Size = ([Runtime.InteropServices.Marshal]::ReadInt32($BSTR,-4)) [PSCustomObject]@{ BSTR = $BSTR Size = $Size Bytes = (0..($Size-1) | Foreach-Object { [Runtime.InteropServices.Marshal]::ReadByte($BSTR,$_) }) } | Write-Output } } Function Read-WorksheetContent { <# .Synopsis Load an excel worksheet into a variable. .Description Load an excel worksheet into a variable. This method requires that the workbook COM object is already opened. You are responsible for closing and releasing COM objects. For a more user friendly method, please see the function Read-WorkbookContent .PARAMETER Workbook A Workbook COM object .PARAMETER Worksheet The name or index of the worksheet to load .PARAMETER NamedColumns If set, the function uses the first line as headers for the data. Otherwise it is returned as a simple array .Example # Load the first sheet of a workbook $Excel = New-Object -ComObject Excel.Application $Excel.Visible = $true $Workbook = $Excel.Workbooks.Open("MyXlsFile.xlsx") $data = Read-WorksheetContent -Workbook $Workbook -Worksheet 1 $Workbook.Close .Example # Load a named sheet of a workbook, use the first line a column headers $Excel = New-Object -ComObject Excel.Application $Excel.Visible = $true $Workbook = $Excel.Workbooks.Open("MyXlsFile.xlsx") $data = Read-WorksheetContent -Workbook $Workbook -Worksheet "Name of the Sheet" -NamedColumns $Workbook.Close #> param( [parameter(Mandatory)] [__ComObject]$Workbook, $Worksheet = 1, [switch]$NamedColumns ) Process { $data = @() $activity = "Loading worksheet [$($Worksheet)] from workbook [$($Workbook.Name)]" Write-Progress -Id 1 -ParentId 0 -Activity $activity -PercentComplete 0 try { $sheet = $Workbook.Sheets.item($Worksheet); $sheet.Activate(); $endColumn = $sheet.UsedRange.SpecialCells(11).Column $endRow = $sheet.UsedRange.SpecialCells(11).Row if($NamedColumns) { # Load Column Titles $columnTitles = @() for($i=1; $i -le 1; $i++) { for($j=1; $j -le $endColumn; $j++) { Write-Progress -Id 1 -ParentId 0 -Activity $activity -PercentComplete ([int](($j/$endColumn*100)*(20/100))) Write-Progress -Id 2 -ParentId 1 -Activity "Loading Column ${j}" -PercentComplete ([int]($j/$endColumn*100)) $columnTitles+=$sheet.Rows.Item($i).Columns.Item($j).Text } } # Load Rows Write-Progress -Id 1 -ParentId 0 -Activity "Loading Worksheet $($Worksheet)" -PercentComplete 10 for($i=2; $i -le $endRow; $i++) { $row = @{} for($j=1; $j -le $endColumn; $j++) { Write-Progress -Id 1 -ParentId 0 -Activity $activity -PercentComplete ([int](20+(($i/$endRow*100)*(80/100)))) Write-Progress -Id 2 -ParentId 1 -Activity "Loading Row ${i}" -PercentComplete ([int]($i/$endRow*100)) $row.Add(($columnTitles[$j-1] -replace "[\W]+","_"), $sheet.Rows.Item($i).Columns.Item($j).Text) } $data+=[pscustomobject]$row } } else { # Load Rows for($i=1; $i -le $endRow; $i++) { $row = [ordered]@{} for($j=1; $j -le $endColumn; $j++) { Write-Progress -Id 1 -ParentId 0 -Activity $activity -PercentComplete ([int]($i/$endRow*100)) Write-Progress -Id 2 -ParentId 1 -Activity "Loading Row ${i}" -PercentComplete ([int]($i/$endRow*100)) $row.Add($j, $sheet.Rows.Item($i).Columns.Item($j).Text) } $data+=[pscustomobject]$row } } } finally { Write-Progress -Id 1 -ParentId 0 -Activity $activity -PercentComplete 100 -Complete } return $data } } Function Compare-SecureString { <# .SYNOPSIS Compare two secure string, without decrypting them .Description Compare two secure string, without decrypting them .PARAMETER SecureString1 The first secure string .PARAMETER SecureString2 The second secure string .Example Compare-SecureString $ss1 $ss2 #> [CmdletBinding()] [OutputType([bool])] param ( [Parameter(Position=0)] [Security.SecureString]$LeftSecureString, [Parameter(Position=1)] [Security.SecureString]$RightSecureString ) Process { $Left = Get-SecureStringByteArray $LeftSecureString $Right = Get-SecureStringByteArray $RightSecureString if($Left.Size -eq $Right.Size) { ((0..(($Left.Size)-1) | Where-Object { $Left.Bytes[$_] -ne $Right.Bytes[$_]}).Length -eq 0) | Write-Output } else { $false | Write-Output } } } Function ConvertFrom-HtmlEncoded { <# .SYNOPSIS Replaces all html entities by the characters they represent .Description Replaces all html entities by the characters they represent .PARAMETER InputString The input string .Example 'Hé mec!' | ConvertFrom-HtmlEncoded #> [CmdletBinding()] [OutputType([string])] param ( [Parameter(ValueFromPipeline, Position=0)] [AllowEmptyString()] [Alias('String')] [String]$InputString ) Process { if($InputString) { [System.Web.HttpUtility]::HtmlDecode($InputString) | Write-Output } } } Function ConvertFrom-UrlEncoded { <# .SYNOPSIS Replaces all url encoded characters by the characters they represent .Description Replaces all url encoded characters by the characters they represent .PARAMETER InputString The input string .Example 'Father+&+son' | ConvertFrom-UrlEncoded #> [CmdletBinding()] [OutputType([string])] param ( [Parameter(ValueFromPipeline, Position=0)] [AllowEmptyString()] [Alias('String')] [String]$InputString ) Process { if($InputString) { [System.Web.HttpUtility]::UrlDecode($InputString) | Write-Output } } } Function ConvertTo-CamelCase { <# .SYNOPSIS Convert a string to CamelCase .Description Convert a string to CamelCase and remove non alpha-numeric characters .PARAMETER InputString The input string .Example # Convert 'hello world-123' to 'HelloWorld123' 'hello world 123' | ConvertTo-CamelCase #> [CmdletBinding()] [OutputType([string])] param ( [Parameter(ValueFromPipeline, Position=0)] [AllowEmptyString()] [Alias('String')] [String]$InputString, [switch]$KeepNonAlphanumericCharacters ) Process { if($Inputstring) { $CamelCase = (Get-Culture).TextInfo.ToTitleCase($InputString) if($KeepNonAlphanumericCharacters) { $CamelCase | Write-Output } else { $CamelCase -Replace '\W' | Write-Output } } } } Function ConvertTo-CamelCaseIndexedHashtable { <# .SYNOPSIS Convert each Key of a hashtable to CamelCase .Description Convert each Key of a hashtable to CamelCase and remove non alpha-numeric characters .PARAMETER InputHashtable The input hashtable .Example @{'hello world'='Hello World'} | ConvertTo-CamelCaseIndexedHashtable #> [CmdletBinding()] [OutputType([hashtable])] param ( [Parameter(ValueFromPipeline, Position=0)] [AllowEmptyCollection()] [AllowNull()] [Alias('Input','Hashtable')] [hashtable]$InputHashtable ) Process { [hashtable]$OutputHashTable if($InputHashtable) { foreach($k in $InputHashtable.Keys) { $OutputHashTable += @{ ($k | ConvertTo-CamelCase) = $InputHashtable.$k } } } $OutputHashTable | Write-Output } } Function ConvertTo-CamelCaseList { <# .SYNOPSIS Convert each value in a list to CamelCase .Description Convert each value in a list to CamelCase and remove non alpha-numeric characters .PARAMETER InputList The input list .Example @{'hello world','Hello World'} | ConvertTo-CamelCaseList #> [CmdletBinding()] [OutputType([string[]])] param ( [Parameter(ValueFromPipeline, Position=0)] [AllowEmptyCollection()] [AllowNull()] [Alias('Input','List')] [string[]]$InputList ) Process { [string[]]$OutputList = @() if($InputList) { foreach($v in $InputList) { $OutputList += ($v | ConvertTo-CamelCase) } } $OutputList | Write-Output } } Function ConvertTo-FileName { <# .SYNOPSIS Modifiy a string to make it suitable for a filename .Description Modifiy a string to make it suitable for a filename by removing or replacing any forbidden characeter .PARAMETER InputString The input string .Example 'Meta\Null.txt' | ConvertTo-FileName #> [CmdletBinding()] [OutputType([string])] param ( [Parameter(ValueFromPipeline, Position=0)] [AllowEmptyString()] [Alias('String')] [String]$InputString, [Parameter(Position=1)] [AllowEmptyString()] [String]$ReplaceBy = [string]::empty, [switch]$SwallowConsecutive ) Begin { $InvalidChars = [System.IO.Path]::GetInvalidFileNameChars() -join '' if($SwallowConsecutive) { $RegExInvalid = "[{0}]+" -f [RegEx]::Escape($InvalidChars) } else { $RegExInvalid = "[{0}]" -f [RegEx]::Escape($InvalidChars) } } Process { if($InputString) { $InputString -replace $RegExInvalid,$ReplaceBy | Write-Output } } } Function ConvertTo-Hash { <# .Synopsis Convert a string to a Hash .Description Convert a string to a Hash using powershell's default algorithm (SHA256, at the time of writing) .PARAMETER InputString The input string .Example 'Hello MetaNull' | ConvertTo-Hash #> [CmdletBinding()] [OutputType([String])] param ( # String to encode [Parameter(ValueFromPipeline, Position=0)] [AllowEmptyString()] [Alias('String')] [string]$InputString ) Process { if($InputString) { $stringAsStream = [System.IO.MemoryStream]::new() $writer = [System.IO.StreamWriter]::new($stringAsStream) $writer.write($InputString) $writer.Flush() $stringAsStream.Position = 0 Get-FileHash -InputStream $stringAsStream | Select-Object -ExpandProperty Hash | Write-Output } } } Function ConvertTo-HtmlEncoded { <# .SYNOPSIS Replaces all unsupported html characters by hmtl entities .Description Replaces all unsupported html characters by hmtl entities .PARAMETER InputString The input string .Example 'H� mec!' | ConvertTo-HtmlEncoded #> [CmdletBinding()] [OutputType([string])] param ( [Parameter(ValueFromPipeline, Position=0)] [AllowEmptyString()] [Alias('String')] [String]$InputString ) Process { if($InputString) { [System.Web.HttpUtility]::HtmlEncode($InputString) | Write-Output } } } Function ConvertTo-Label { <# .Synopsis Convert a string to a "label". .Description Convert a string to a "label": - The label is made of lower case alpha numerical characters separated by single dash characters. - It always starts by a letter. - No trailing dashes at the end. The function can optionally convert &|.@ characters in their text representation (and, or, dot, at) .Example # Format a string "SC.IIT.DIS.3" | ConvertTo-Label .Example # Format an email address "pascal.havelange@eesc.europa.eu" | ConvertTo-Label -ReplacePunctuation #> [CmdletBinding()] [OutputType([String])] param ( # String to encode [Parameter(ValueFromPipeline, Position=0)] [AllowEmptyString()] [Alias('String')] [string]$InputString, # Replace &,|,@,. by and,or,at,dot [switch]$ReplacePunctuation ) Process { if($InputString) { # Remove non ASCII (note: mind the "C" in "-creplace" !) [string]$OutputString = ($InputString -creplace "\P{IsBasicLatin}") if($ReplacePunctuation) { $OutputString = ($OutputString -replace "(\s*\.+\s*)+"," dot ") $OutputString = ($OutputString -replace "(\s*[&]+\s*)+"," and ") $OutputString = ($OutputString -replace "(\s*[\|]+\s*)+"," or ") $OutputString = ($OutputString -replace "(\s*[@]+\s*)+"," at ") } # Remove non alnum characters $OutputString = ($OutputString -replace "[\W]+","-") # Remove head/tail dashes, remove head numbers $OutputString = ($OutputString -replace "(^[\d-]*|[-]*$)") # Return lower case string $OutputString.ToLower() | Write-Output } } } Function ConvertTo-LabelIndexedHashtable { <# .SYNOPSIS Convert each Key of a hashtable to "label" .Description Convert each Key of a hashtable to "label" - The label is made of lower case alpha numerical characters separated by single dash characters. - It always starts by a letter. - No trailing dashes at the end. The function can optionally convert &|.@ characters in their text representation (and, or, dot, at) .PARAMETER InputString The input string .Example @{'hello world'='Hello World'} | ConvertTo-LabelIndexedHashtable #> [CmdletBinding()] [OutputType([hashtable])] param ( [Parameter(ValueFromPipeline, Position=0)] [AllowEmptyCollection()] [AllowNull()] [Alias('Input','Hashtable')] [hashtable]$InputHashtable, # Replace &,|,@,. by and,or,at,dot [switch]$ReplacePunctuation ) Process { [hashtable]$OutputHashTable if($InputHashtable) { foreach($k in $InputHashtable.Keys) { $OutputHashTable += @{ ($k | ConvertTo-Label -ReplacePunctuation:$ReplacePunctuation) = $InputHashtable.$k } } } $OutputHashTable | Write-Output } } Function ConvertTo-LabelList { <# .SYNOPSIS Convert each value in a list to a "label" .Description Convert each value in a list to a "label" - The label is made of lower case alpha numerical characters separated by single dash characters. - It always starts by a letter. - No trailing dashes at the end. The function can optionally convert &|.@ characters in their text representation (and, or, dot, at) .PARAMETER InputList The input list .Example @{'hello world','Hello World'} | ConvertTo-CamelCaseList #> [CmdletBinding()] [OutputType([string[]])] param ( [Parameter(ValueFromPipeline, Position=0)] [AllowEmptyCollection()] [AllowNull()] [Alias('Input','List')] [string[]]$InputList, # Replace &,|,@,. by and,or,at,dot [switch]$ReplacePunctuation ) Process { [string[]]$OutputList = @() if($InputList) { foreach($v in $InputList) { $OutputList += ($v | ConvertTo-Label -ReplacePunctuation:$ReplacePunctuation) } } $OutputList | Write-Output } } Function ConvertTo-UrlEncoded { <# .SYNOPSIS Replaces all unsupported url characters by their escaped representation .Description Replaces all unsupported url characters by their escaped representation .PARAMETER InputString The input string .Example 'Father & Son' | ConvertTo-UrlEncoded #> [CmdletBinding()] [OutputType([string])] param ( [Parameter(ValueFromPipeline, Position=0)] [AllowEmptyString()] [Alias('String')] [String]$InputString ) Process { if($InputString) { [System.Web.HttpUtility]::UrlEncode($InputString) | Write-Output } } } Function ConvertTo-Version { <# .Synopsis Converts a string into a [version] object. .Description Converts a string into a [version] object. Missing Version indicators are replaced by zero (0) .PARAMETER InputString The input string .Example '1.0','1.2.3','1.x.x',12 | ConvertTo-Version #> [CmdletBinding()] [OutputType([version])] param ( # String to encode [Parameter(ValueFromPipeline, Position=0)] [AllowEmptyString()] [Alias('Version','String')] [string]$InputString ) Process { $VersionArray = @(0,0,0,0) if($InputString -match '^\s*(?:(?:v|v\.|ver\.|ver|version)\s*)?(\d+(?:\.\d+)*)') { $InputArray = ($Matches[1] -split '\.',5) for($i = 0; ($i -lt $VersionArray.Length) -and ($i -lt $InputArray.Length); $i ++) { $VersionArray[$i] = [int]$InputArray[$i] } } return ([version]::new($VersionArray -join '.')) } } Function ConvertTo-XDocument { <# .SYNOPSIS Convert a piece of html into a XDocument .Description Convert a piece of (well formed) html into a XDocument .PARAMETER InputString The input string. It must contain a valid piece of XHTML #> [CmdletBinding()] [OutputType([System.Xml.Linq.XDocument])] param ( [Parameter(ValueFromPipeline, Position=0)] [AllowEmptyString()] [Alias('String','Html')] [String[]]$InputString, [Parameter(Position = 1)] [AllowEmptyCollection()] [AllowNull()] [string[]]$Namespaces ) Process { [UtilsXDocument]::HtmlToXDocument($InputString,$Namespaces) | Write-Output <# $Document = Get-HtmlDoctype $Document += '<xml' $Namespaces | Where-Object {$_ } | ForEach-Object { $Document += "xmlns:$($_)=""$($_)""" } $Document += '>' $InputString | Foreach-Object { $Document += $_ } $Document += '</xml>' [System.Xml.Linq.XDocument]::Parse($Document) | Write-Output #> } } Function Format-FixedWidthString { <# .SYNOPSIS Successively Trim and Pad a string to make it fit a certain number of charaters .Description Successively Trim and Pad a string to make it fit a certain number of charaters .PARAMETER InputString The input string .Example 'Hello World!' | Format-FixedWidthString -Length 7 # Returns: "Hell..." #> [CmdletBinding()] [OutputType([string])] param ( [Parameter(ValueFromPipeline, Position=0)] [AllowEmptyString()] [AllowNull()] [Alias('String')] [String]$InputString, [Parameter(Mandatory)] [int] $Length ) Process { if($null -eq $InputString) { # If empty, return a blank string of $Length characters [string]::empty.PadRight($Length,' ') | Write-Output } elseif($InputString.Length -gt ($Length)) { # If longer than $Length, Trim the excess characters, and add '...' $InputString.SubString(0,$Length -3).PadRight($Length,'.') | Write-Output } else { # If Smaller than $Length, Pad string with spaces to match the requested $Length $InputString.PadRight($Length,' ') | Write-Output } } } Function Get-CachedCredential { <# .SYNOPSIS Retrieve (securely) stored credentials from the Registry .Description Retrieve (securely) stored credentials from the Registry .PARAMETER Name The credentials' name .Example Get-CachedCredential -Name 'AtlassianToken' #> [CmdletBinding(DefaultParameterSetName='List')] [OutputType([PSCredential])] param ( [Parameter(Mandatory,Position=0,ParameterSetName='Named')] [string]$Name ) Begin { $RegistryKey = "$CRegistryHive\Credential" } Process { Get-Item -Path $RegistryKey | Get-ChildItem | Where-Object { ($PsCmdlet.ParameterSetName -eq 'List') -or ($_.PSChildName -eq ($Name -replace '\W+','-')) } | Foreach-Object { $_ | Set-ItemProperty -Name LastAccess -Value (Get-Date -Format 'yyyyMMddHHmmss') | Out-Null $Properties = $_ | Get-ItemProperty New-Object System.Management.Automation.PSCredential -ArgumentList ($Properties.UserName, ($Properties.Password | ConvertTo-SecureString)) } } } Function Get-Country { <# .SYNOPSIS Load the list of Country from the repository of the Publication Office .DESCRIPTION Load the list of Country from the repository of the Publication Office .PARAMETER EU Limit the resultset to EU Country .PARAMETER EFTA Limit the resultset to EURO Zone Country .PARAMETER NATO Limit the resultset to NATO Country .EXAMPLE # Get All Countries Get-Country | Format-Table .EXAMPLE # Get EU Countries Get-Country -EU | Format-Table .EXAMPLE # Get EU Countries, keeping only the firs toccurence of each country Get-UtilsCountry -EU | Group-Object Country | Foreach-Object { $_.Group | Select-Object -First 1 } | Format-table .EXAMPLE # Get all Countries from the European Continent Get-Country | Where-Object { $_.Continent -match 'EUROPE' } .NOTES Documentation: https://codyburleson.com/blog/sparql-examples-select https://publications.europa.eu/webapi/rdf/sparql https://publications.europa.eu/resource/authority/country #> [CmdletBinding(DefaultParameterSetName='All')] [OutputType([UtilsCountry[]])] param( [Parameter(Mandatory,Position=0,ParameterSetName='Identifier_Search')] [Alias('Id')] [string] $Identifier, [Parameter(Mandatory,ParameterSetName='EU')] [switch] $EU, [Parameter(Mandatory,ParameterSetName='EURO')] [switch] $EURO, [Parameter(Mandatory,ParameterSetName='NATO')] [switch] $NATO, [Parameter(Mandatory,ParameterSetName='Schengen')] [switch] $Schengen, [Parameter(Mandatory,ParameterSetName='OTHER')] [switch] $OTHER, [Parameter(Mandatory=$false,ParameterSetName='All')] [switch] $All ) Begin { [UtilsCountry]::ClearAllCountries() $SparqlQuery = @" PREFIX authority: <http://publications.europa.eu/resource/authority/> PREFIX ns9: <http://publications.europa.eu/ontology/authority/> PREFIX ns5: <http://publications.europa.eu/ontology/euvoc#> PREFIX ogcgs: <http://www.opengis.net/ont/geosparql#> SELECT DISTINCT ?country ?identifier ?protocol ?name_en ?iso_3166_1_alpha_2 ?iso_3166_1_alpha_3 ?iso_3166_1_num ?phone_prefix ?iana_domain ?unsd_geoscheme ?status ?alt_name_en ?continent ?language ?classification FROM <http://publications.europa.eu/resource/authority/country> WHERE { ?country dc:identifier ?identifier ; ns5:status ?status ; dcterms:type ?classification ; dcterms:language ?language . ?country skos:notation ?iso_3166_1_alpha_2 . FILTER (datatype(?iso_3166_1_alpha_2) = <http://publications.europa.eu/ontology/euvoc#ISO_3166_1_ALPHA_2>) ?country skos:notation ?iso_3166_1_alpha_3 . FILTER (datatype(?iso_3166_1_alpha_3) = <http://publications.europa.eu/ontology/euvoc#ISO_3166_1_ALPHA_3>) ?country skos:notation ?iso_3166_1_num . FILTER (datatype(?iso_3166_1_num) = <http://publications.europa.eu/ontology/euvoc#ISO_3166_1_NUM>) OPTIONAL { ?country skos:notation ?phone_prefix . FILTER (datatype(?phone_prefix) = <http://publications.europa.eu/ontology/euvoc#PHONE_PREFIX>) } OPTIONAL { ?country skos:notation ?iana_domain . FILTER (datatype(?iana_domain) = <http://publications.europa.eu/ontology/euvoc#IANA_DOMAIN>) } OPTIONAL { ?country skos:notation ?unsd_geoscheme . FILTER (datatype(?unsd_geoscheme) = <http://publications.europa.eu/ontology/euvoc#UNSD_GEOSCHEME>) } OPTIONAL { ?country ogcgs:sfWithin ?continent . } # ?country authority:op-code ?code ; OPTIONAL { # Get the EU protocol display order ?country ns9:protocol.order ?protocol . } OPTIONAL { # Get the name in english ?country skos:prefLabel ?name_en . FILTER (langMatches(lang(?name_en), "en")) } OPTIONAL { # Get the alternate name in english ?country skos:altLabel ?alt_name_en . FILTER (langMatches(lang(?alt_name_en), "en")) } # NO! # ?country ns5:context <http://publications.europa.eu/resource/authority/use-context/PUB> ; # PUBLIC Context ?? not complete list ?country ns5:status <http://publications.europa.eu/resource/authority/concept-status/CURRENT> . # CURRENT data only (no deprecated data) ## FILTERS ## } ORDER BY ?protocol "@ } Process { <# <dcterms:type rdf:resource="http://publications.europa.eu/resource/authority/membership-classification/EURO"/> <dcterms:type rdf:resource="http://publications.europa.eu/resource/authority/membership-classification/SCHENGEN"/> <dcterms:type rdf:resource="http://publications.europa.eu/resource/authority/membership-classification/NATO"/> <dcterms:type rdf:resource="http://publications.europa.eu/resource/authority/membership-classification/EU"/> <dcterms:type rdf:resource="http://publications.europa.eu/resource/authority/membership-classification/EEA"/> #> if($Identifier) { $Query = $SparqlQuery.Replace('## FILTERS ##',"?country dc:identifier ""$Identifier""") } elseif( $EU ) { $Query = $SparqlQuery.Replace('## FILTERS ##',"?country dcterms:type <http://publications.europa.eu/resource/authority/membership-classification/EU> . # EU Languages Only") } elseif( $EURO ) { $Query = $SparqlQuery.Replace('## FILTERS ##',"?country dcterms:type <http://publications.europa.eu/resource/authority/membership-classification/EURO> . # EFTA Languages Only") } elseif( $NATO ) { $Query = $SparqlQuery.Replace('## FILTERS ##',"?country dcterms:type <http://publications.europa.eu/resource/authority/membership-classification/NATO> . # Non-EU Languages Only") } elseif( $Schengen) { $Query = $SparqlQuery.Replace('## FILTERS ##',"?country dcterms:type <http://publications.europa.eu/resource/authority/membership-classification/SCHENGEN> . # EFTA Languages Only") } elseif( $OTHER ) { $Query = $SparqlQuery.Replace('## FILTERS ##',"?country dcterms:type <http://publications.europa.eu/resource/authority/membership-classification/OTHER> . # Non-EU Languages Only") } else { $Query = $SparqlQuery } $Query | Write-Debug $Groupable = 'continent','language','classification','unsd_geoscheme' $Query | Invoke-PublicationOffice | Group-Object country | Foreach-Object { $Group = $_.Group $Country = $Group[0] $Groupable | Foreach-Object { $property = $_ $Country.$property = ($Group | Group-Object $property | Select-Object -ExpandProperty Name -Unique <#| Foreach-Object { $_|Write-Verbose ; $_ }#>) } [UtilsCountry]::FromCustomObject($Country) } } } Function Get-FileNameExtension { <# .SYNOPSIS Get the 'extension' from a filename .Description Get the 'extension' from a filename .PARAMETER InputString The input string .Example 'MetaNull.txt' | Get-FileNameExtension #> [CmdletBinding()] [OutputType([bool])] param ( # string to process [Parameter(ValueFromPipeline, Position=0)] [AllowEmptyString()] [Alias('String','Path','Leaf','Filename')] [String]$InputString ) Process { [System.IO.Path]::GetExtension($InputString) | Write-Output } } Function Get-Language { <# .SYNOPSIS Load the list of Language from the repository of the Publication Office .DESCRIPTION Load the list of Language from the repository of the Publication Office .PARAMETER EU Limit the resultset to EU Languages .PARAMETER EFTA Limit the resultset to EFTA Languages .PARAMETER Other Limit the resultset to non EU and non EFTA Languages .PARAMETER All Get all languages .EXAMPLE # Get All Languages Get-Language | Format-Table .EXAMPLE # Get EU Languages Get-Language -EU | Format-Table .EXAMPLE # Get all Germanic Languages Get-Language | Where-Object { $_.Definition -match 'germanic' } | Select-Object Identifier,Name,Definition .NOTES Documentation: https://codyburleson.com/blog/sparql-examples-select https://publications.europa.eu/webapi/rdf/sparql https://publications.europa.eu/resource/authority/language #> [CmdletBinding(DefaultParameterSetName='All')] [OutputType([UtilsLanguage[]])] param( [Parameter(Mandatory,Position=0,ParameterSetName='Identifier_Search')] [Alias('Id')] [string] $Identifier, [Parameter(Mandatory,ParameterSetName='EU')] [switch] $EU, [Parameter(Mandatory,ParameterSetName='EFTA')] [switch] $EFTA, [Parameter(Mandatory,ParameterSetName='OTHER')] [switch] $OTHER, [Parameter(Mandatory=$false,ParameterSetName='All')] [switch] $All ) Begin { [UtilsLanguage]::ClearAllLanguages() $SparqlQuery = @" PREFIX authority: <http://publications.europa.eu/resource/authority/> PREFIX ns9: <http://publications.europa.eu/ontology/authority/> PREFIX ns5: <http://publications.europa.eu/ontology/euvoc#> SELECT ?language ?identifier ?protocol ?name_en ?definition_en ?name ?iso ?iso_639_1 ?iso_639_3 ?status ?classification # ?code ?iso_639_2b ?iso_639_2t FROM <http://publications.europa.eu/resource/authority/language> WHERE { ?language dc:identifier ?identifier ; ns5:status ?status ; dcterms:type ?classification . ?language skos:notation ?iso_639_1 . FILTER (datatype(?iso_639_1) = <http://publications.europa.eu/ontology/euvoc#ISO_639_1>) ?language skos:notation ?iso_639_3 . FILTER (datatype(?iso_639_3) = <http://publications.europa.eu/ontology/euvoc#ISO_639_3>) ?language skos:notation ?iso . FILTER (datatype(?iso) = <http://publications.europa.eu/ontology/euvoc#PUB_LNGISO>) # ?language authority:op-code ?code ; # ?language skos:notation ?iso_639_2b . # FILTER (datatype(?iso_639_2b) = <http://publications.europa.eu/ontology/euvoc#ISO_639_2B>) # # ?language skos:notation ?iso_639_2t . # FILTER (datatype(?iso_639_2t) = <http://publications.europa.eu/ontology/euvoc#ISO_639_2T>) OPTIONAL { # Get the EU protocol display order ?language ns9:protocol.order ?protocol . } OPTIONAL { # Get the name and definition in english ?language skos:prefLabel ?name_en ; skos:definition ?definition_en . FILTER (langMatches(lang(?name_en), "en")) FILTER (langMatches(lang(?definition_en), "en")) } OPTIONAL { # Get the name in its original language ?language skos:notation ?iso_639_1 ; skos:prefLabel ?name . FILTER (datatype(?iso_639_1) = <http://publications.europa.eu/ontology/euvoc#ISO_639_1>) FILTER (langMatches(lang(?name), ?iso_639_1)) } ?language ns5:context <http://publications.europa.eu/resource/authority/use-context/PUB> ; # PUBLIC Context ns5:status <http://publications.europa.eu/resource/authority/concept-status/CURRENT> . # CURRENT data only (no deprecated data) ## FILTERS ## } # LIMIT 100 "@ } Process { if($Identifier) { $Query = $SparqlQuery.Replace('## FILTERS ##',"?language dc:identifier ""$Identifier""") } elseif( $EU ) { $Query = $SparqlQuery.Replace('## FILTERS ##',"?language dcterms:type <http://publications.europa.eu/resource/authority/membership-classification/EU> . # EU Languages Only") } elseif( $EFTA ) { $Query = $SparqlQuery.Replace('## FILTERS ##',"?language dcterms:type <http://publications.europa.eu/resource/authority/membership-classification/EFTA> . # EFTA Languages Only") } elseif( $OTHER ) { $Query = $SparqlQuery.Replace('## FILTERS ##',"?language dcterms:type <http://publications.europa.eu/resource/authority/membership-classification/OTHER> . # Non-EU Languages Only") } else { $Query = $SparqlQuery } $Query | Write-Debug $Groupable = 'iso','classification' $Query | Invoke-PublicationOffice | Group-Object language | Foreach-Object { $Group = $_.Group $Language = $Group[0] $Groupable | Foreach-Object { $property = $_ $Language.$property = ($Group | Group-Object $property | Select-Object -ExpandProperty Name -Unique <#| Foreach-Object { $_|Write-Verbose ; $_ }#>) } [UtilsLanguage]::FromCustomObject($Language) } } } Function Get-ServiceExt { <# .SYNOPSIS Find a service by Name, DisplayName or BinaryPathName .PARAMETER PathExpression Search using REGEX on the service's binary Path .PARAMETER NameExpression Search using REGEX on the service's name .PARAMETER DisplayNameExpression Search using REGEX on the service's DisplayName .PARAMETER Service Search using the passed Service object #> [CmdletBinding(DefaultParameterSetName = 'Name')] [OutputType([System.ServiceProcess.ServiceController])] param( [Parameter(Position=0,Mandatory=$false,ValueFromPipeline,ParameterSetName='Name')] [AllowEmptyString()] [AllowNull()] [string]$Name, [Parameter(Position=0,Mandatory,ParameterSetName='Path')] [string]$Path, [Parameter(Position=0,Mandatory,ParameterSetName='NameExpression')] [string]$NameExpression, [Parameter(Position=0,Mandatory,ParameterSetName='DisplayName')] [string]$DisplayName, [Parameter(Position=0,Mandatory,ParameterSetName='DisplayNameExpression')] [string]$DisplayNameExpression, [Parameter(Position=0,Mandatory,ValueFromPipeline,ParameterSetName='Service')] [System.ServiceProcess.ServiceController]$Service ) Begin { $ErrorActionPreference = 'SilentlyContinue' } Process { Get-Service | Where-Object { ($PsCmdlet.ParameterSetName -eq 'Name' -and -not $Name) ` -or ($PsCmdlet.ParameterSetName -eq 'Name' -and $_.Name -eq $Name) ` -or ($PsCmdlet.ParameterSetName -eq 'Path' -and $_.Path -match "^(?:^|"")?($([regex]::Escape($Path)))(?:""|$|\b)?") ` -or ($PsCmdlet.ParameterSetName -eq 'NameExpression' -and $_.Name -match $NameExpression) ` -or ($PsCmdlet.ParameterSetName -eq 'DisplayName' -and $_.DisplayName -eq $DisplayName) ` -or ($PsCmdlet.ParameterSetName -eq 'DisplayNameExpression' -and $_.DisplayName -match $DisplayNameExpression) ` -or ($PsCmdlet.ParameterSetName -eq 'Service' -and $_.ServiceName -eq $Service.ServiceName ) } | Foreach-Object { # if($PSVersionTable.PSVersion.Major -lt 6) { if(-not $_.BinaryPathName) { $Cim = Get-CimInstance -Query "select * from Win32_Service where Name = ""$($_.Name)""" -Verbose:$false $_ | Add-Member -MemberType NoteProperty -Name BinaryPathName -Value $Cim.PathName | Out-Null } $_ | Write-Output } } } Function Invoke-PublicationOffice { <# .SYNOPSIS Perform a SPARQL query upon the Publication Office .PARAMETER SparqlQuery The SPARQL query string .EXAMPLE # Get a list of EU languages # $Query = @" # PREFIX authority: <http://publications.europa.eu/resource/authority/> # PREFIX ns9: <http://publications.europa.eu/ontology/authority/> # SELECT ?language ?identifier ?name ?protocol ?classification # FROM <http://publications.europa.eu/resource/authority/language> # WHERE { # ?language dc:identifier ?identifier ; # dcterms:type ?classification ; # skos:prefLabel ?name . # FILTER (langMatches(lang(?name), "en")) # Get the name in English (generally available) # OPTIONAL { # Get the EU protocol display order (only available for EU languages) # ?language ns9:protocol.order ?protocol . # } # ?language dcterms:type <http://publications.europa.eu/resource/authority/membership-classification/EU> . # EU Language Only # } # "@ $Query | Invoke-PublicationOffice | Format-Table #> [CmdletBinding()] [OutputType([PSCustomObject[]])] param( [Parameter(Mandatory,ValueFromPipeline,Position=0)] [Alias('Sparql','Query','q')] [string] $SparqlQuery ) Begin { $ServiceUri = [uri]::new('https://publications.europa.eu/webapi/rdf/sparql') } Process { $Arguments = @{ 'default-graph-uri' = $null query = $SparqlQuery format = 'application/json' timeout = '0' debug = 'on' } $QueryUri = [System.UriBuilder]::new($ServiceUri) $QueryUri.Query = (($Arguments.Keys | Foreach-Object { "$($_)=$([System.Web.HttpUtility]::UrlEncode($Arguments.$_))" }) -join '&') $QueryUri.Uri.ToString() | Write-Verbose $JsonResponse = Invoke-WebRequest $QueryUri.Uri.ToString() | ConvertFrom-Json $JsonResponse.results.bindings | Foreach-Object { $Binding = $_ $Line = New-Object psobject $JsonResponse.head.vars | Foreach-Object { $Variable = $_ switch($Binding.$Variable.type) { "uri" { $Line | Add-Member -MemberType NoteProperty -Name $Variable -Value ([uri]::new($Binding.$Variable.value)) } default { $Line | Add-Member -MemberType NoteProperty -Name $Variable -Value ($Binding.$Variable.value) } } } $Line | Write-Output } } } Function Join-String { <# .Synopsis Join pipeline input into a single string .Description Join pipeline input into a single string .Example # Join a list into a string 'a','b','c' | Join-String #> [CmdletBinding()] [OutputType([String])] param ( # String to encode [Parameter(ValueFromPipeline, Position=0)] [Alias('string')] [string]$InputString, [Parameter(Mandatory=$false,Position=1)] [string]$Glue ) Begin { $Collect = @() } End { if(-not $Glue) { $Glue = '' } $Collect -join $Glue } Process { $Collect += $InputString } } Function Read-WorkbookContent { <# .Synopsis Load an excel workbook into a variable. .Description This function loads one or several sheets from an excel file. The XLS file must not be opened by another user. .PARAMETER WorkbookUrl The Path or Url of the Excel file .PARAMETER Worksheets An ordered hashtable representing the sheets to load. Keys of the hashtable are used as index in the returned array. Values of the hashtables are the names or indexes of the sheets. .PARAMETER NamedColumns If set, the function uses the first line as headers for the data. Otherwise it is returned as a simple array (This paramtere is applied to all the loaded sheets). .PARAMETER FrefreshAll If set, all Queries in the workbook will be refreshed (Depending on the queries' sources, Excel may prompt for authentication) .Example # Load the first sheet of a workbook $data = Read-WorkbookContent -WorkbookUrl "MyXlsFile.xlsx" .Example # Load the first three sheets of a workbook $data = Read-WorkbookContent -WorkbookUrl "MyXlsFile.xlsx" -Worksheets @{"sheet1"=1;"sheet2"=2;"sheet3"=3}) .Example # Load two named sheets of a workbook, use the first line a column headers $data = Read-WorkbookContent -WorkbookUrl "MyXlsFile.xlsx" -Worksheets (@{"sheet1"="Name of the First Sheet";"sheet2"="Name of the Second Sheet"}) -NamedColumns .Example # Load two named sheets of a workbook, use the first line a column headers $sheets = [ordered] @{"sheet1"="Name of the First Sheet";"sheet2"="Name of the Second Sheet"} $data = Read-WorkbookContent -WorkbookUrl "MyXlsFile.xlsx" -Worksheets $sheets -NamedColumns #> param( [parameter(Mandatory=$true,ValueFromPipeline=$true)]$WorkbookUrl, $Worksheets = [ordered]@{"data"="1"}, [switch]$NamedColumns, [switch]$RefreshAll ) Process { $activity = "Loading workbook from [$($WorkbookUrl)]" Write-Progress -Id 0 -Activity $activity -PercentComplete 0 Try { $Excel = New-Object -ComObject Excel.Application $Excel.Visible = $false $Workbook = $Excel.Workbooks.Open($WorkbookUrl) if($RefreshAll) { Write-Progress -Id 1 -ParentId 0 -Activity "Refreshing all queries" -PercentComplete 0 #$Excel.Visible = $false $Workbook.RefreshAll() #$Excel.Visible = $true Write-Progress -Id 1 -ParentId 0 -Activity "Refreshing all queries" -PercentComplete 100 -Complete } $sheetIndex = 1 $sheetCount = $Worksheets.Count $WorkbookData=[ordered]@{} foreach($sheet in $Worksheets.GetEnumerator()) { Write-Progress -Id 0 -Activity $activity -PercentComplete ([int]($sheetIndex++/$sheetCount)*100) if($NamedColumns) { $content = (Read-WorksheetContent -Workbook $Workbook -Worksheet ($sheet.Value) -NamedColumns) } else { $content = (Read-WorksheetContent -Workbook $Workbook -Worksheet ($sheet.Value)) } $WorkbookData.Add($sheet.Key, $content) } return [pscustomobject]$WorkbookData } Finally { Write-Progress -Id 1 -ParentId 0 -Activity "Closing Workbook" -PercentComplete 0 if( $Workbook -ne $null ) { $Workbook.Close($false) [System.Runtime.InteropServices.Marshal]::ReleaseComObject($Workbook) | Out-Null $Workbook = $null } if( $Excel -ne $null ) { $Excel.Visible = $true [System.Runtime.InteropServices.Marshal]::ReleaseComObject($Excel) | Out-Null $Excel = $null } [System.GC]::Collect() [System.GC]::WaitForPendingFinalizers() Write-Progress -Id 1 -ParentId 0 -Activity "Closing Workbook" -PercentComplete 100 -Complete Write-Progress -Id 0 -Activity $activity -PercentComplete 100 -Complete } } } Function Remove-CachedCredential { <# .SYNOPSIS Remove (securely) stored credentials from the Registry .Description Remove (securely) stored credentials from the Registry .PARAMETER Name The credentials' name .Example Remove-CachedCredential -Name 'AtlassianToken' .Example # Remove all Remove-CachedCredential #> [CmdletBinding(DefaultParameterSetName='List',SupportsShouldProcess)] param ( [Parameter(Mandatory,Position=0,ParameterSetName='Named')] [string]$Name ) Begin { $RegistryKey = "$CRegistryHive\Credential" } Process { Get-Item -Path $RegistryKey | Get-ChildItem | Where-Object { ($PsCmdlet.ParameterSetName -eq 'List') -or ($_.PSChildName -eq ($Name -replace '\W+','-')) } | Foreach-Object { if($PSCmdlet.ShouldProcess("Registry Key '$($_.Name)' ")){ $_ | Remove-Item | Write-Output } } } } Function Remove-ServiceExt { <# .SYNOPSIS Remove a service by Name .PARAMETER PathExpression Search using REGEX on the service's binary Path .PARAMETER NameExpression Search using REGEX on the service's name .PARAMETER DisplayNameExpression Search using REGEX on the service's DisplayName .PARAMETER Service Search using the passed Service object #> [CmdletBinding(DefaultParameterSetName = 'Name',SupportsShouldProcess)] [OutputType([void])] param( [Parameter(Position=0,Mandatory=$false,ValueFromPipeline,ParameterSetName='Name')] [AllowEmptyString()] [AllowNull()] [string]$Name, [Parameter(Position=0,Mandatory,ParameterSetName='Path')] [string]$Path, [Parameter(Position=0,Mandatory,ParameterSetName='NameExpression')] [string]$NameExpression, [Parameter(Position=0,Mandatory,ParameterSetName='DisplayName')] [string]$DisplayName, [Parameter(Position=0,Mandatory,ParameterSetName='DisplayNameExpression')] [string]$DisplayNameExpression, [Parameter(Position=0,Mandatory,ValueFromPipeline,ParameterSetName='Service')] [System.ServiceProcess.ServiceController]$Service, [switch]$Stop ) Process { $GetServiceExtParameters = $PSBoundParameters.PSObject.Copy() $GetServiceExtParameters.Remove('Stop') | Out-Null Get-ServiceExt @GetServiceExtParameters | Foreach-Object { if($PSCmdlet.ShouldProcess("Windows Service '$($_.ServiceName)' (Status: $($_.Status))")){ if($Stop -and $_.Status -notin ([System.ServiceProcess.ServiceControllerStatus]::Stopped,[System.ServiceProcess.ServiceControllerStatus]::StopPending)) { "Stopping service '$($_.ServiceName)'" | Write-Verbose $_ | Stop-Service } "Removing service ServiceName" | Write-Verbose #if($PSVersionTable.PSVersion.Major -ge 6) { if( (Get-Command Remove-Service -ErrorAction SilentlyContinue)) { $_ | Remove-Service } else { &(Get-Command sc.exe) delete ($_.ServiceName) if( $LASTEXITCODE -ne 0 ) { "Error removing service '$($_.ServiceName)' (sc.exe returned #$LASTEXITCODE)" | Write-Error } } } } } } Function Select-Xpath { <# .SYNOPSIS Use XPath on a blob of (xhtml) text .Description Use XPath on a blob of (xhtml) text. .PARAMETER InputDocument The input XML onwhich to run xpath .PARAMETER Xpath The xpath query string .PARAMETER Namespaces A list of additional NS to declare .EXAMPLE # Get URL from all hyperlinks in a page $Html | ConvertTo-XDocument | Select-Xpath -XPath '//a/@href/text()' #> [CmdletBinding()] [OutputType([object[]])] param ( [Parameter(Mandatory,Position=0)] [string]$XPath, [Parameter(Position=1)] [AllowEmptyCollection()] [AllowNull()] [string[]]$Namespaces, [Parameter(ValueFromPipeline,Mandatory,Position=2)] [Alias('Document','Xml','Node')] [object]$InputDocument ) Process { if($null -ne $Namespaces -and $Namespaces.Length) { $NS = @{} $Namespaces | ForEach-Object { $NS.$_ = $_ } $InputDocument | Select-Xml -Namespace $NS -XPath $Xpath } else { $InputDocument | Select-Xml -XPath $Xpath } } } Function Set-CachedCredential { <# .SYNOPSIS Store credentials (securely) in the Registry .Description Store credentials (securely) in the Registry .PARAMETER InputCredential The credentials to store .PARAMETER Name The credentials' name .Example Get-Credential -Message 'Your credential' | Set-CachedCredential #> [CmdletBinding(SupportsShouldProcess)] param ( [Parameter(Mandatory,ValueFromPipeline,Position=0)] [Alias('Credential')] [PSCredential]$InputCredential, [Parameter(Mandatory,Position=1)] [String]$Name ) Process { $PSHPName = "$CRegistryHive\Credential$($Name -replace '\W+','-')" if($PSCmdlet.ShouldProcess("Registry Key '$($PSHPName)' ")){ $RegistryKey = "$CRegistryHive\Credential" if(-not (Test-Path -Path $RegistryKey)) { New-Item -Path $RegistryKey -ErrorAction Stop -Force | Out-Null } New-Item -Path $RegistryKey -Name ($Name -replace '\W+','-') -ErrorAction Stop | Foreach-Object { $_ | New-ItemProperty -PropertyType String -Name UserName -Value $InputCredential.UserName | Out-Null $_ | New-ItemProperty -PropertyType String -Name Password -Value ($InputCredential.Password | ConvertFrom-SecureString) | Out-Null $_ | New-ItemProperty -PropertyType String -Name LastAccess -Value (Get-Date -Format 'yyyyMMddHHmmss') | Out-Null $_ | Get-Item | Write-Output } } } } Function Test-ElevatedPrivilege { <# .SYNOPSIS Test if the current powershell is running with Elevated Privileges .Description Test if the current powershell is running with Elevated Privileges .Example Test-ElevatedPrivilege #> [CmdletBinding()] [OutputType([bool])] param ( ) Process { ([Security.Principal.WindowsPrincipal][Security.Principal.WindowsIdentity]::GetCurrent()).IsInRole([Security.Principal.WindowsBuiltInRole]::Administrator) | Write-Output } } Function Test-FileName { <# .SYNOPSIS Test if a string is suitable for a filename .Description Test if a string is suitable for a filename by checking if it contains any forbidden characeter .PARAMETER InputString The input string .Example 'MetaNull.txt' | Test-FileName #> [CmdletBinding()] [OutputType([bool])] param ( # string to process [Parameter(ValueFromPipeline, Position=0)] [AllowEmptyString()] [Alias('String')] [String]$InputString ) Begin { $InvalidChars = [System.IO.Path]::GetInvalidFileNameChars() -join '' $RegExInvalid = "[{0}]" -f [RegEx]::Escape($InvalidChars) } Process { $InputString -notmatch $RegExInvalid | Write-Output } } Function Test-Label { <# .SYNOPSIS Test the format of a "label". .DESCRIPTION Test the format of a "label". - The label is made of lower case alpha numerical characters separated by single dash characters. - It always starts by a letter. - No trailing dashes at the end. .EXAMPLE # Test the format of a label "SC.IIT.DIS.3" | Test-Label # -> $false .EXAMPLE # Test the format of a label "sc-iit-dis-3" | Test-Label # -> $true #> [CmdletBinding()] [OutputType([String])] param ( # String to encode [Parameter(ValueFromPipeline, Position=0)] [AllowEmptyString()] [Alias('String')] [string]$InputString ) Process { $InputString -cmatch '^[a-z][a-z0-9-]+[a-z0-9]$' | Write-Output } } |