Framework/Helpers/Helpers.ps1
using namespace Newtonsoft.Json Set-StrictMode -Version Latest class Helpers { static AbstractClass($obj, $classType) { $type = $obj.GetType() if ($type -eq $classType) { throw("Class '$type' must be inherited") } } static [string] SanitizeFolderName($folderPath) { return ($folderPath -replace '[<>:"/\\|?*]', ''); } static [string] ConvertObjectToString([PSObject] $dataObject, [bool] $defaultPsOutput) { [string] $msg = ""; if ($dataObject) { if ($dataObject.GetType().FullName -eq "System.Management.Automation.ErrorRecord") { if ($defaultPsOutput) { $msg = $dataObject.ToString(); } else { $msg = ($dataObject | Out-String) + "`r`nStackTrace: " + $dataObject. ScriptStackTrace } } else { if ($defaultPsOutput -or $dataObject.GetType() -eq [string]) { $msg = $dataObject | Out-String; } else { try { #$msg = $dataObject | ConvertTo-Json -Depth 5 | Out-String; #$msg = [Helpers]::ConvertToJsonCustom($dataObject); $msg = [Helpers]::ConvertToPson($dataObject); } catch { $e = $_ $msg = $dataObject | Format-List | Out-String; } $msg = $msg.Trim(); } } } return $msg; } static [JsonSerializerSettings] $SerializerSettings = $null; hidden static [JsonSerializerSettings] GetSerializerSettings() { if (-not [Helpers]::SerializerSettings) { $settings = [JsonSerializerSettings]::new(); $settings.Converters.Add([Converters.StringEnumConverter]::new()); $settings.Formatting = [Formatting]::Indented; $settings.NullValueHandling = [NullValueHandling]::Ignore; $settings.ReferenceLoopHandling = [ReferenceLoopHandling]::Ignore; [Helpers]::SerializerSettings = $settings; } return [Helpers]::SerializerSettings; } static [string] ConvertToJson([PSObject] $dataObject) { if ($dataObject) { if ($dataObject.GetType() -eq [System.Object[]] -and $dataObject.Count -ne 0) { $list = New-Object -TypeName "System.Collections.Generic.List[$($dataObject[0].GetType().fullname)]"; $dataObject | ForEach-Object { if ($_) { $list.Add($_); } } return [JsonConvert]::SerializeObject($list, [Helpers]::GetSerializerSettings()); } return [JsonConvert]::SerializeObject($dataObject, [Helpers]::GetSerializerSettings()); } return ""; } static [string] ConvertToJsonCustom([PSObject] $Object) { Set-StrictMode -Off $res = [Helpers]::ConvertToJsonCustomNotStrict($Object, 10, 10, $false) Set-StrictMode -Version Latest return $res } static [string] ConvertToPson([PSObject] $Object) { Set-StrictMode -Off $res = [Helpers]::ConvertToPsonNotStrict($Object, 10, 10, $false, $false, (Get-Variable -Name PSVersionTable).Value.PSVersion) Set-StrictMode -Version Latest return $res } static [string] ConvertToJsonCustomNotStrict([PSObject] $Object, [Int]$Depth, [Int]$Layers, [bool]$IsWind) { $Format = $Null $Quote = If ($Depth -le 0) {""} Else {""""} $Space = If ($Layers -le 0) {""} Else {" "} If ($Object -eq $Null) { return "null"} Else { $JSON = If ($Object -is "Array") { $Format = "[", ",$Space", "]" If ($Depth -gt 1) { For ($i = 0; $i -lt $Object.Count; $i++) { [Helpers]::ConvertToJsonCustomNotStrict($Object[$i], $Depth - 1, $Layers - 1, $IsWind) } } } ElseIf ($Object -is "Xml") { $String = New-Object System.IO.StringWriter $Object.Save($String) $Xml = "'" + ([String]$String).Replace("`'", "'") + "'" If ($Layers -le 0) { ($Xml -Replace "\r\n\s*", "") -Replace "\s+", " " } ElseIf ($Layers -eq 1) { $Xml } Else { $Xml.Replace("`r`n", "`r`n ") } $String.Dispose() } ElseIf ($Object -is "Enum") { "$Quote$($Object.ToString())$Quote" } ElseIf ($Object -is "DateTime") { "$Quote$($Object.ToString("o"))$Quote" } ElseIf ($Object -is "String") { $Object = ConvertTo-Json $Object -Depth 1 "$Object" } ElseIf ($Object -is "Boolean") { If ($Object) {"true"} Else {"false"} } ElseIf ($Object -is "Char") { "$Quote$Object$Quote" } ElseIf ($Object -is "guid") { "$Quote$Object$Quote" } ElseIf ($Object -is "ValueType") { $Object } ElseIf ($Object.Keys -ne $Null) { $Format = "{", ",$Space", "}" If ($Depth -gt 1) { $Object.GetEnumerator() | ForEach-Object { $Quote + $_.Name + $Quote + "$Space`:$Space" + ([Helpers]::ConvertToJsonCustomNotStrict($_.Value, $Depth - 1, $Layers - 1, $IsWind)) } } } ElseIf ($Object -is "Object") { If ($Object -is "System.Management.Automation.ErrorRecord" -and !$IsWind) { $Depth = 3 $Layers = 3 $IsWind = $true } $Format = "{", ",$Space", "}" If ($Depth -gt 1) { $Object | Get-Member -MemberType Properties | ForEach-Object { $Quote + $_.Name + $Quote + "$Space`:$Space" + ([Helpers]::ConvertToJsonCustomNotStrict($Object.$($_.Name), $Depth - 1, $Layers - 1, $IsWind)) } } } Else {$Object} If ($Format) { $JSON = $Format[0] + (& { If (($Layers -le 1) -or ($JSON.Count -le 0)) { $JSON -Join $Format[1] } Else { ("`r`n" + ($JSON -Join "$($Format[1])`r`n")).Replace("`r`n", "`r`n ") + "`r`n" } }) + $Format[2] } return "$JSON" } } # Adapted from https://stackoverflow.com/questions/15139552/save-hash-table-in-powershell-object-notation-pson # Added case for enum # PSON - PowerShell Object Notation static [string] ConvertToPsonNotStrict($Object, [Int]$Depth, [Int]$Layers, [bool]$IsWind, [bool]$Strict, [Version]$Version) { $Format = $Null $Quote = If ($Depth -le 0) {""} Else {""""} $Space = If ($Layers -le 0) {""} Else {" "} If ($Object -eq $Null) { return "`$Null" } Else { $Type = "[" + $Object.GetType().Name + "]" $PSON = If ($Object -is "Array") { $Format = "@(", ",$Space", ")" If ($Depth -gt 1) { For ($i = 0; $i -lt $Object.Count; $i++) { [Helpers]::ConvertToPsonNotStrict($Object[$i], $Depth - 1, $Layers - 1, $IsWind, $Strict, $Version) } } } ElseIf ($Object -is "Xml") { $Type = "[Xml]" $String = New-Object System.IO.StringWriter $Object.Save($String) $Xml = "'" + ([String]$String).Replace("`'", "'") + "'" If ($Layers -le 0) {($Xml -Replace "\r\n\s*", "") -Replace "\s+", " "} ElseIf ($Layers -eq 1) {$Xml} Else {$Xml.Replace("`r`n", "`r`n ")} $String.Dispose() } ElseIf ($Object -is "Enum") { "$Quote$($Object.ToString())$Quote" } ElseIf ($Object -is "DateTime") { "$Quote$($Object.ToString('s'))$Quote" } ElseIf ($Object -is "String") { 0..11 | ForEach-Object { $Object = $Object.Replace([String]"```'""`0`a`b`f`n`r`t`v`$"[$_], ('`' + '`''"0abfnrtv$'[$_]))}; "$Quote$Object$Quote" } ElseIf ($Object -is "Boolean") { If ($Object) {"`$True"} Else {"`$False"} } ElseIf ($Object -is "Char") { If ($Strict) {[Int]$Object} Else {"$Quote$Object$Quote"} } ElseIf ($Object -is "guid") { "$Quote$Object$Quote" } ElseIf ($Object -is "ValueType") { $Object } ElseIf ($Object.Keys -ne $Null) { If ($Type -eq "[OrderedDictionary]") {$Type = "[Ordered]"} $Format = "@{", ";$Space", "}" If ($Depth -gt 1) { $Object.GetEnumerator() | ForEach { $Quote + $_.Name + $Quote + "$Space=$Space" + ([Helpers]::ConvertToPsonNotStrict($_.Value, $Depth - 1, $Layers - 1, $IsWind, $Strict, $Version)) } } } ElseIf ($Object -is "Object") { If ($Object -is "System.Management.Automation.ErrorRecord" -and !$IsWind) { $Depth = 3 $Layers = 3 $IsWind = $true } If ($Version -le [Version]"2.0") {$Type = "New-Object PSObject -Property "} $Format = "@{", ";$Space", "}" If ($Depth -gt 1) { $Object.PSObject.Properties | ForEach { $Quote + $_.Name + $Quote + "$Space=$Space" + ([Helpers]::ConvertToPsonNotStrict($_.Value, $Depth - 1, $Layers - 1, $IsWind, $Strict, $Version)) } } } Else {$Object} If ($Format) { $PSON = $Format[0] + (& { If (($Layers -le 1) -or ($PSON.Count -le 0)) { $PSON -Join $Format[1] } Else { ("`r`n" + ($PSON -Join "$($Format[1])`r`n")).Replace("`r`n", "`r`n ") + "`r`n" } }) + $Format[2] } If ($Strict) { return "$Type$PSON" } Else { return "$PSON" } } } static [string] GetAccessToken([string] $resourceAppIdUri, [string] $tenantId) { $rmContext = Get-AzureRmContext -ErrorAction Stop; if ([string]::IsNullOrEmpty($tenantId)) { $tenantId = $rmContext.Tenant.TenantId } $environment = [Microsoft.Azure.Commands.Common.Authentication.Models.AzureEnvironment] $rmContext.Environment $resourceEnum = $environment.Endpoints.GetEnumerator() | Where-Object { ([string] $_.Value).Trimend('/') -eq $resourceAppIdUri.Trimend('/') } | Select-Object -First 1 if (!$resourceEnum) { throw "The resource url is not supported. Supported values are: " + ($environment.Endpoints.Values -join ", ") } $authFactory = [Microsoft.Azure.Commands.Common.Authentication.IAuthenticationFactory] [Microsoft.Azure.Commands.Common.Authentication.AzureSession]:: AuthenticationFactory $authResult = $authFactory.Authenticate(` $rmContext.Account, ` $rmContext.Environment, ` $tenantId, ` [System.Security.SecureString] $null, ` [Microsoft.Azure.Commands.Common.Authentication.ShowDialog]::Auto, ` $resourceEnum.Key) if ($null -eq $authResult) { throw "Unable to get access token. Authentication Failed." } if (-not $authResult.AccessToken) { throw "Unable to get access token. Authentication Failed." } return $authResult.AccessToken } static [string] GetAccessToken([string] $resourceAppIdUri) { return [Helpers]::GetAccessToken($resourceAppIdUri, ""); } static [System.Management.Automation.RuntimeDefinedParameterDictionary] NewDynamicParam([string] $parameterName, [string[]] $options, [bool] $mandatory, [string] $parameterSetName, [string] $helpMessage) { # Create the dictionary $RuntimeParameterDictionary = New-Object System.Management.Automation.RuntimeDefinedParameterDictionary # Create the collection of attributes $AttributeCollection = New-Object System.Collections.ObjectModel.Collection[System.Attribute] # Create and set the parameters' attributes $ParameterAttribute = New-Object System.Management.Automation.ParameterAttribute #$ParameterAttribute.ValueFromPipeline = $false #$ParameterAttribute.ValueFromPipelineByPropertyName = $false $ParameterAttribute.Mandatory = $mandatory if (-not [string]::IsNullOrEmpty($helpMessage)) { $ParameterAttribute.HelpMessage = $helpMessage; } if (-not [string]::IsNullOrEmpty($parameterSetName)) { $ParameterAttribute.ParameterSetName = $parameterSetName; } # Add the attributes to the attributes collection $AttributeCollection.Add($ParameterAttribute) # Generate and set the ValidateSet $ValidateSetAttribute = New-Object System.Management.Automation.ValidateSetAttribute($options) # Add the ValidateSet to the attributes collection $AttributeCollection.Add($ValidateSetAttribute) # Create and return the dynamic parameter $RuntimeParameter = New-Object System.Management.Automation.RuntimeDefinedParameter($parameterName, [string], $AttributeCollection) $RuntimeParameterDictionary.Add($parameterName, $RuntimeParameter) return $RuntimeParameterDictionary } static [bool] CompareObject($referenceObject, $differenceObject) { $result = $true; ($referenceObject | Get-Member -MemberType Properties) | ForEach-Object { $refProp = $referenceObject."$($_.Name)"; if ($differenceObject | Get-Member -Name $_.Name) { $compareProp = $differenceObject."$($_.Name)"; if ($refProp.GetType().Name -eq "PSCustomObject") { $result = $result -and [Helpers]::CompareObject($refProp, $compareProp); } else { $result = $result -and (((Compare-Object $refProp $compareProp) | Where-Object { $_.SideIndicator -eq "<=" } | Measure-Object).Count -eq 0) } } else { $result = $false; } } return $result; } static [bool] CheckMember([PSObject] $refObject, [string] $memberPath) { [bool]$result = $false; if ($refObject) { $properties = @(); $properties += $memberPath.Split("."); if ($properties.Count -gt 0) { $currentItem = $properties.Get(0); if (-not [string]::IsNullOrEmpty($currentItem)) { if (($refObject | Get-Member -Name $currentItem) -and $refObject.$currentItem) { $result = $true; if ($properties.Count -gt 1) { $result = $result -and [Helpers]::CheckMember($refObject.$currentItem, [string]::Join(".", $properties[1..($properties.length - 1)])); } } } } } return $result; } static [PSObject] NewAzsdkCompliantStorage([string]$Name, [string]$ResourceGroup, [string]$Location) { $storageSku = "Standard_GRS" $storageObject = $null try { #create storage $newStorage = New-AzureRmStorageAccount -ResourceGroupName $ResourceGroup -Name $Name -Type $storageSku -Location $Location ` -Kind BlobStorage -AccessTier Cool -EnableEncryptionService Blob -ErrorAction Stop $retryAccount = 0 do { $storageObject = Get-AzureRmStorageAccount -ResourceGroupName $ResourceGroup -Name $Name -ErrorAction SilentlyContinue Start-Sleep -seconds 2 $retryAccount++ }while (!$storageObject -and $retryAccount -ne 6) if ($storageObject) { #create alert rules $emailAction = New-AzureRmAlertRuleEmail -SendToServiceOwners -ErrorAction Stop $targetId = $storageObject.Id + "/services/" + "blob" $alertName = $Name + "alert" Add-AzureRmMetricAlertRule -Location $storageObject.Location -MetricName AnonymousSuccess -Name $alertName -Operator GreaterThan ` -ResourceGroup $storageObject.ResourceGroupName ` -TargetResourceId $targetId ` -Threshold 0 -TimeAggregationOperator Total -WindowSize 01:00:00 -Actions $emailAction ` -WarningAction SilentlyContinue ` -ErrorAction Stop #set diagnostics on $currentContext = $storageObject.Context Set-AzureStorageServiceLoggingProperty -ServiceType Blob -LoggingOperations All -Context $currentContext -RetentionDays 365 -PassThru -ErrorAction Stop Set-AzureStorageServiceMetricsProperty -MetricsType Hour -ServiceType Blob -Context $currentContext -MetricsLevel ServiceAndApi -RetentionDays 365 -PassThru -ErrorAction Stop } } catch { #cleanup storage if error occurs if ((Find-AzureRmResource -ResourceGroupNameEquals $ResourceGroup -ResourceNameEquals $Name|Measure-Object).Count -gt 0) { Remove-AzureRmStorageAccount -ResourceGroupName $ResourceGroup -Name $Name -Force -ErrorAction SilentlyContinue } } return $storageObject } } |