1
# Copyright 2014-2015 Cloudbase Solutions Srl
3
# Licensed under the Apache License, Version 2.0 (the "License"); you may
4
# not use this file except in compliance with the License. You may obtain
5
# a copy of the License at
7
# http://www.apache.org/licenses/LICENSE-2.0
9
# Unless required by applicable law or agreed to in writing, software
10
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
11
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
12
# License for the specific language governing permissions and limitations
15
Import-Module JujuLogging
17
function Convert-FileToBase64{
20
This powershell commandlet converts an entire file, byte by byte to base64 and returns the string.
22
WARNING: Do not use this to convert large files, as it reads the entire contents of a file
23
into memory. This function may be useful to transfer small amounts of data over a relation
24
without having to worry about encoding or escaping, preserving at the same time any
28
The path to the file you want to convert. It works for any type of file. Take great care not to
29
try and convert large files.
33
[parameter(Mandatory=$true)]
38
if(!(Test-Path $File)) {
39
Throw "No such file: $File"
42
if($f.Length -gt 1MB -and !$Force) {
43
Throw "File is too big to convert (> 1MB). Use -Force to do it anyway..."
45
$ct = [System.IO.File]::ReadAllBytes($File)
46
$b64 = [Convert]::ToBase64String($ct)
51
function Write-FileFromBase64 {
54
Helper function that converts base64 to bytes and then writes that stream to a file.
56
Destination file to write to.
62
[Parameter(Mandatory=$true)]
64
[Parameter(Mandatory=$true, ValueFromPipeline=$true)]
68
$bytes = [Convert]::FromBase64String($Content)
69
[System.IO.File]::WriteAllBytes($File, $bytes)
73
function ConvertTo-Base64 {
76
Convert string to its base64 representation
78
String to be converted to base64
82
[Parameter(Mandatory=$true, ValueFromPipeline=$true)]
86
$x = [System.Convert]::ToBase64String([System.Text.Encoding]::Unicode.GetBytes($Content))
91
function ConvertFrom-Base64 {
94
Convert base64 back to string
100
[Parameter(Mandatory=$true, ValueFromPipeline=$true)]
104
$x = [System.Text.Encoding]::Unicode.GetString([System.Convert]::FromBase64String($content))
109
function Get-EncryptedString {
112
This is just a helper function that converts a plain string to a secure string and returns the encrypted
113
string representation.
115
The string you want to encrypt
119
[Parameter(Mandatory=$true, ValueFromPipeline=$true)]
123
$ret = ConvertTo-SecureString -AsPlainText -Force $Content | ConvertFrom-SecureString
128
function Get-DecryptedString {
131
Decrypt a securestring back to its plain text representation.
133
The encrypted content to decrypt.
135
This function is only meant to be used with encrypted strings, not binary.
139
[Parameter(Mandatory=$true, ValueFromPipeline=$true)]
143
$c = ConvertTo-SecureString $Content
144
$dec = [System.Runtime.InteropServices.Marshal]::SecureStringToCoTaskMemUnicode($c)
145
$ret = [System.Runtime.InteropServices.Marshal]::PtrToStringUni($dec)
146
[System.Runtime.InteropServices.Marshal]::ZeroFreeCoTaskMemUnicode($dec)
151
function Get-UserPath {
154
Returns the $env:PATH variable for the current user.
157
return [System.Environment]::GetEnvironmentVariable("PATH", "User")
161
function Get-SystemPath {
164
Returns the system wide default $env:PATH.
167
return [System.Environment]::GetEnvironmentVariable("PATH", "Machine")
171
function Compare-ScriptBlocks {
174
Compare two script blocks
175
.PARAMETER ScriptBlock1
177
.PARAMETER ScriptBlock2
182
[Parameter(Mandatory=$true)]
184
[System.Management.Automation.ScriptBlock]$ScriptBlock1,
185
[Parameter(Mandatory=$true)]
187
[System.Management.Automation.ScriptBlock]$ScriptBlock2
190
$sb1 = $ScriptBlock1.ToString()
191
$sb2 = $ScriptBlock2.ToString()
192
return ($sb1.CompareTo($sb2) -eq 0)
196
function Compare-Arrays {
199
Compare two arrays. Returns a boolean value that determines whether or not the arrays are equal.
201
First array to compare
203
Second array to compare
207
[Parameter(Mandatory=$true)]
209
[System.Object[]]$Array1,
210
[Parameter(Mandatory=$true)]
212
[System.Object[]]$Array2
215
return (((Compare-Object $Array1 $Array2).InputObject).Length -eq 0)
219
function Compare-HashTables {
222
Compare two arrays. Returns a boolean value that determines whether or not the arrays are equal. This function only works for flat hashtables.
224
First array to compare
226
Second array to compare
230
[Parameter(Mandatory=$true)]
232
[HashTable]$HashTable1,
233
[Parameter(Mandatory=$true)]
235
[HashTable]$HashTable2
238
if ($HashTable1.Count -ne $HashTable2.Count) {
241
foreach ($i in $HashTable1.Keys) {
242
if (($HashTable2.ContainsKey($i) -eq $false) -or ($HashTable1[$i] -ne $HashTable2[$i])) {
250
function Start-ExternalCommand {
253
Helper function to execute a script block and throw an exception in case of error.
254
.PARAMETER ScriptBlock
255
Script block to execute
256
.PARAMETER ArgumentList
257
A list of parameters to pass to Invoke-Command
258
.PARAMETER ErrorMessage
259
Optional error message. This will become part of the exception message we throw in case of an error.
263
[Parameter(Mandatory=$true)]
265
[ScriptBlock]$ScriptBlock,
266
[array]$ArgumentList=@(),
267
[string]$ErrorMessage
271
# Leftover exit code. Some other process failed, and this
272
# function was called before it was resolved.
273
# There is no way to determine if the ScriptBlock contains
274
# a powershell commandlet or a native application. So we clear out
275
# the LASTEXITCODE variable before we execute. By this time, the value of
276
# the variable is not to be trusted for error detection anyway.
279
$res = Invoke-Command -ScriptBlock $ScriptBlock -ArgumentList $ArgumentList
282
Throw ("Command exited with status: {0}" -f $LASTEXITCODE)
284
throw ("{0} (Exit code: $LASTEXITCODE)" -f $ErrorMessage)
290
function Start-ExecuteWithRetry {
293
In some cases a command may fail several times before it succeeds, be it because of network outage, or a service
294
not being ready yet, etc. This is a helper function to allow you to execute a function or binary a number of times
295
before actually failing.
297
Its important to note, that any powershell commandlet or native command can be executed using this function. The result
298
of that command or powershell commandlet will be returned by this function.
300
Only the last exception will be thrown, and will be logged with a log level of ERROR.
301
.PARAMETER ScriptBlock
302
The script block to run.
303
.PARAMETER MaxRetryCount
304
The number of retries before we throw an exception.
305
.PARAMETER RetryInterval
306
Number of seconds to sleep between retries.
307
.PARAMETER ArgumentList
308
Arguments to pass to your wrapped commandlet/command.
311
# If the computer just booted after the machine just joined the domain, and your charm starts running,
312
# it may error out until the security policy has been fully applied. In the bellow example we retry 10
313
# times and wait 10 seconds between retries before we give up. If successful, $ret will contain the result
314
# of Get-ADUser. If it does not, an exception is thrown.
315
$ret = Start-ExecuteWithRetry -ScriptBlock {
317
} -MaxRetryCount 10 -RetryInterval 10
321
[Parameter(Mandatory=$true)]
323
[ScriptBlock]$ScriptBlock,
324
[int]$MaxRetryCount=10,
325
[int]$RetryInterval=3,
326
[array]$ArgumentList=@()
329
$currentErrorActionPreference = $ErrorActionPreference
330
$ErrorActionPreference = "Continue"
335
$res = Invoke-Command -ScriptBlock $ScriptBlock `
336
-ArgumentList $ArgumentList
337
$ErrorActionPreference = $currentErrorActionPreference
339
} catch [System.Exception] {
341
if ($retryCount -gt $MaxRetryCount) {
342
$ErrorActionPreference = $currentErrorActionPreference
346
Write-HookTracebackToLog $_ -LogLevel WARNING
348
Start-Sleep $RetryInterval
355
function Get-SanePath {
358
There are some situations in which the $env:PATH variable may contain duplicate paths. This function returns
359
a sanitized $env:PATH without any duplicates.
363
$arrayPath = $path.Split(';')
364
$arrayPath = $arrayPath | Select-Object -Unique
365
$newPath = $arrayPath -join ';'
370
function Add-ToUserPath {
373
Permanently add an additional path to $env:PATH for current user, and also set the current $env:PATH to the new value.
375
Extra path to add to $env:PATH
379
[Parameter(Mandatory=$true)]
383
$currentPath = Get-SanePath
384
if ($Path -in $env:Path.Split(';')){
387
$newPath = $currentPath + ";" + $Path
388
Start-ExternalCommand -Command {
390
} -ErrorMessage "Failed to set user path"
395
function Get-MarshaledObject {
398
Get a base64 encoded representation of a yaml encoded powershell object. "Why?" you might ask. Well, in some cases you
399
may need to send more complex information through a relation to another charm. This function allows you to send simple
400
powershell objects (hashtables, arrays, etc) as base64 encoded strings. This function first encodes them to yaml, and
401
then to base64 encoded strings.
403
This also allows us to send the same information to any kind of charm that can unmarshal yaml to a native type (say python).
407
ConvertTo-Base64 uses utf-16-le encoding for objects
411
$obj = @{"Hello"="world";}
412
Get-MarshaledObject -Object $obj
413
ewANAAoAIAAgACAAIAAiAEgAZQBsAGwAbwAiADoAIAAgACIAdwBvAHIAbABkACIADQAKAH0A
417
[Parameter(Mandatory=$true)]
422
$encoded = $Object | ConvertTo-Yaml
423
$b64 = ConvertTo-Base64 $encoded
428
function Get-UnmarshaledObject {
431
Try to convert a base64 encoded string back to a powershell object.
433
The base64 encoded representation of the object we want to unmarshal.
437
[Parameter(Mandatory=$true)]
442
$decode = ConvertFrom-Base64 $Object
443
$ret = $decode | ConvertFrom-Yaml
448
function Get-CmdStringFromHashtable {
451
Convert a hashtable to a command line key/value string. Values for hashtable keys must be string or int. The result is usually suitable for native commands executed via cmd.exe.
452
.PARAMETER Parameters
453
hashtable containing command line parameters.
461
Get-CmdStringFromHashtable $params
462
age=20 firstname=John lastname=Doe
466
[Parameter(Mandatory=$true)]
468
[Hashtable]$Parameters
472
foreach($i in $Parameters.GetEnumerator()) {
473
$args += $i.key + "=" + $i.value + " "
479
function Get-EscapedQuotedString {
485
return "'" + $value.Replace("'", "''") + "'"
489
function Get-PSStringParamsFromHashtable {
492
Convert a hashtable to a powershell command line options. Values can be any powershell objects.
493
.PARAMETER Parameters
494
hashtable containing command line parameters.
502
Get-PSStringParamsFromHashtable $params
503
-age 20 -firstname John -lastname Doe
507
[Parameter(Mandatory=$true)]
512
foreach($i in $params.GetEnumerator()) {
513
$args += @(("-" + $i.key), $i.value)
516
return $args -join " "
520
Export-ModuleMember -Function * -Alias *