diff --git a/documentation/Debugging-StaticAnalysis-Errors.md b/documentation/Debugging-StaticAnalysis-Errors.md index 2974529049a5..801784a17401 100644 --- a/documentation/Debugging-StaticAnalysis-Errors.md +++ b/documentation/Debugging-StaticAnalysis-Errors.md @@ -56,7 +56,6 @@ Most help issues that cause StaticAnalysis to fail occur when help has not been ### Example Issues Example issues occur when your changed markdown files in the `help` folder (_e.g.,_ `src/Accounts/Accounts/help`) violate PowerShell language best practices. Please follow the suggestion displayed in "Remediation" entry for each violation listed in `ExampleIssues.csv`. If you have an issue with severity 0 or 1 that has been approved by the Azure PowerShell team, you can suppress them following these steps: - - Download the `ExampleIssues.csv` file from the CI pipeline artifacts - Open the file using a text editor (such as VS Code) and copy each of the errors you'd like to suppress - Paste each of these errors into the `ExampleIssues.csv` file found in their respective [module folder](../tools/StaticAnalysis/Exceptions) (_e.g.,_ if an example issue is being suppressed for Accounts, then you would paste the corresponding line(s) in the `tools/StaticAnalysis/Exceptions/Az.Accounts/ExampleIssue.csv` file) using the same text editor diff --git a/src/Accounts/Accounts/help/Add-AzEnvironment.md b/src/Accounts/Accounts/help/Add-AzEnvironment.md index 28a77ae285fe..b5d0c7ad02dc 100644 --- a/src/Accounts/Accounts/help/Add-AzEnvironment.md +++ b/src/Accounts/Accounts/help/Add-AzEnvironment.md @@ -3,7 +3,7 @@ external help file: Microsoft.Azure.PowerShell.Cmdlets.Accounts.dll-Help.xml Module Name: Az.Accounts online version: https://docs.microsoft.com/powershell/module/az.accounts/add-azenvironment schema: 2.0.0 ---- +--- # Add-AzEnvironment @@ -160,6 +160,12 @@ TestEnvironment TestRMEndpoint TestADEndpoint/ In this example, we are discovering a new Azure environment from the `https://configuredmetadata.net` Uri. + +### Example 3: Test +```powershell +PS C:\>Add-AzEnvironment -Name Test +``` + ## PARAMETERS ### -ActiveDirectoryEndpoint diff --git a/src/Accounts/Accounts/help/Clear-AzConfig.md b/src/Accounts/Accounts/help/Clear-AzConfig.md index db35d1d16abb..64da8fea51bd 100644 --- a/src/Accounts/Accounts/help/Clear-AzConfig.md +++ b/src/Accounts/Accounts/help/Clear-AzConfig.md @@ -32,6 +32,7 @@ Clears the values of configs that are set by the user. By default all the config ### Example 1 ```powershell +$null = gal Clear-AzConfig -Force ``` diff --git a/src/Accounts/Accounts/help/Connect-AzAccount.md b/src/Accounts/Accounts/help/Connect-AzAccount.md index 6e837e54f0a0..b6f37bc8c739 100644 --- a/src/Accounts/Accounts/help/Connect-AzAccount.md +++ b/src/Accounts/Accounts/help/Connect-AzAccount.md @@ -3,7 +3,7 @@ external help file: Microsoft.Azure.PowerShell.Cmdlets.Accounts.dll-Help.xml Module Name: Az.Accounts online version: https://docs.microsoft.com/powershell/module/az.accounts/connect-azaccount schema: 2.0.0 ---- +--- # Connect-AzAccount diff --git a/src/Accounts/Accounts/help/Disable-AzContextAutosave.md b/src/Accounts/Accounts/help/Disable-AzContextAutosave.md index 206557574fd1..3e2ac7de9f6f 100644 --- a/src/Accounts/Accounts/help/Disable-AzContextAutosave.md +++ b/src/Accounts/Accounts/help/Disable-AzContextAutosave.md @@ -3,7 +3,7 @@ external help file: Microsoft.Azure.PowerShell.Cmdlets.Accounts.dll-Help.xml Module Name: Az.Accounts online version: https://docs.microsoft.com/powershell/module/az.accounts/disable-azcontextautosave schema: 2.0.0 ---- +--- # Disable-AzContextAutosave diff --git a/src/Accounts/Accounts/help/Get-AzDefault.md b/src/Accounts/Accounts/help/Get-AzDefault.md index e179c3844a17..140525c1e22e 100644 --- a/src/Accounts/Accounts/help/Get-AzDefault.md +++ b/src/Accounts/Accounts/help/Get-AzDefault.md @@ -24,7 +24,7 @@ user has set as default in the current context. ### Example 1 ```powershell -Get-AzDefault +get-aZdeFault ``` ```Output diff --git a/src/Accounts/Accounts/help/Invoke-AzRestMethod.md b/src/Accounts/Accounts/help/Invoke-AzRestMethod.md index a57f13462dfa..d8e467b05cd2 100644 --- a/src/Accounts/Accounts/help/Invoke-AzRestMethod.md +++ b/src/Accounts/Accounts/help/Invoke-AzRestMethod.md @@ -3,7 +3,7 @@ external help file: Microsoft.Azure.PowerShell.Cmdlets.Accounts.dll-Help.xml Module Name: Az.Accounts online version: https://docs.microsoft.com/powershell/module/az.accounts/invoke-azrestmethod schema: 2.0.0 ---- +--- # Invoke-AzRestMethod @@ -98,6 +98,24 @@ Content : {"@odata.context":"https://graph.microsoft.com/v1.0/$metadata#users Get current signed in user via MicrosoftGraph API. This example is equivalent to `Get-AzADUser -SignedIn`. +### Example 3 +```powershell +Invoke-AzRestMethod -Name "test" -Path "/subscriptions/{subscription}/resourcegroups/{resourcegroup}/providers/microsoft.operationalinsights/workspaces/{workspace}?api-version={API}" +``` + +```output +{{Add Output Here}} +``` + +### Example 4 +```powershell +``` + +### Example 5 +```powershell +Invoke-AzRestMethod "test" -Path "/subscriptions/{subscription}/resourcegroups/{resourcegroup}/providers/microsoft.operationalinsights/workspaces/{workspace}?api-version={API}" +``` + ## PARAMETERS ### -ApiVersion diff --git a/src/Accounts/Accounts/help/Set-AzContext.md b/src/Accounts/Accounts/help/Set-AzContext.md index ba2f82fbcd59..fe689416de0f 100644 --- a/src/Accounts/Accounts/help/Set-AzContext.md +++ b/src/Accounts/Accounts/help/Set-AzContext.md @@ -3,7 +3,7 @@ external help file: Microsoft.Azure.PowerShell.Cmdlets.Accounts.dll-Help.xml Module Name: Az.Accounts online version: https://docs.microsoft.com/powershell/module/az.accounts/set-azcontext schema: 2.0.0 ---- +--- # Set-AzContext diff --git a/src/AlertsManagement/AlertsManagement/help/Get-AzAlert.md b/src/AlertsManagement/AlertsManagement/help/Get-AzAlert.md index b6186a1e6a5b..dfc4062a5fe6 100644 --- a/src/AlertsManagement/AlertsManagement/help/Get-AzAlert.md +++ b/src/AlertsManagement/AlertsManagement/help/Get-AzAlert.md @@ -57,11 +57,16 @@ Get Alert details by Id (GUID) or Resource Id (Complete ARM Id) ### Example 3 -Get Alerts Information. (autogenerated) +Get Alerts Information. - ```powershell -Get-AzAlert -IncludeContext $true -TimeRange '1h' +Get-AzAlert -IncludeContext $true -TimeRange '1h' -TimeRange '2h' +``` + +### Example 4 + +```powershell +Get-AzAlert -IncludeContext $true -PageCount {} -TimeRange '1h' ``` ## PARAMETERS diff --git a/src/ApiManagement/ApiManagement/help/Add-AzApiManagementApiToGateway.md b/src/ApiManagement/ApiManagement/help/Add-AzApiManagementApiToGateway.md index dc3d018381a8..e1cc449c29b0 100644 --- a/src/ApiManagement/ApiManagement/help/Add-AzApiManagementApiToGateway.md +++ b/src/ApiManagement/ApiManagement/help/Add-AzApiManagementApiToGateway.md @@ -31,6 +31,17 @@ Add-AzApiManagementApiToGateway -Context $ApiMgmtContext -GatewayId "0123456789" This command adds the specified API to the specified Gateway. + +### Example 2 +```powershell +Add-AzApiManagementApiToGateway -Context $ApiMgmtContext -GatewayId "0123456789" -ApiId "0001" +``` + +### Example 3 +```powershell +Add-AzApiManagementApiToGateway -Context -GatewayId "0123456789" -ApiId "0001" +``` + ## PARAMETERS ### -ApiId @@ -181,4 +192,4 @@ This cmdlet supports the common parameters: -Debug, -ErrorAction, -ErrorVariable ## RELATED LINKS -[Remove-AzApiManagementApiFromGateway](./Remove-AzApiManagementApiFromGateway.md) \ No newline at end of file +[Remove-AzApiManagementApiFromGateway](./Remove-AzApiManagementApiFromGateway.md) diff --git a/src/ApiManagement/ApiManagement/help/Remove-AzApiManagement.md b/src/ApiManagement/ApiManagement/help/Remove-AzApiManagement.md index 75b252b23b02..dab920dcfe9b 100644 --- a/src/ApiManagement/ApiManagement/help/Remove-AzApiManagement.md +++ b/src/ApiManagement/ApiManagement/help/Remove-AzApiManagement.md @@ -25,7 +25,7 @@ The **Remove-AzApiManagement** cmdlet removes an Azure API Management service. ### Example 1: Remove an API Management service ```powershell -Remove-AzApiManagement -ResourceGroupName "ContosoGroup02" -Name "ContosoApi" +Remove-AzApiManagement -ResourceGroupName "ContosoGroup02" -Name "ContosoApi" -Test ``` This command removes the API Management service named ContosoApi. diff --git a/src/Compute/Compute/help/Add-AzVMDataDisk.md b/src/Compute/Compute/help/Add-AzVMDataDisk.md index 0a80c53c19c5..7490c89ebaa0 100644 --- a/src/Compute/Compute/help/Add-AzVMDataDisk.md +++ b/src/Compute/Compute/help/Add-AzVMDataDisk.md @@ -41,7 +41,7 @@ $VirtualMachine = New-AzVMConfig -VMName "VirtualMachine07" -VMSize "Standard_A1 $DataDiskVhdUri01 = "https://contoso.blob.core.windows.net/test/data1.vhd" $DataDiskVhdUri02 = "https://contoso.blob.core.windows.net/test/data2.vhd" $DataDiskVhdUri03 = "https://contoso.blob.core.windows.net/test/data3.vhd" -$VirtualMachine = Add-AzVMDataDisk -VM $VirtualMachine -Name 'DataDisk1' -Caching 'ReadOnly' -DiskSizeInGB 10 -Lun 0 -VhdUri $DataDiskVhdUri01 -CreateOption Empty +$VirtualMachine = Add-AzVMDataDisk $VirtualMachine 'DataDisk1' -Caching 'ReadOnly' -DiskSizeInGB 10 -Lun 0 -VhdUri $DataDiskVhdUri01 -CreateOption Empty $VirtualMachine = Add-AzVMDataDisk -VM $VirtualMachine -Name 'DataDisk2' -Caching 'ReadOnly' -DiskSizeInGB 11 -Lun 1 -VhdUri $DataDiskVhdUri02 -CreateOption Empty $VirtualMachine = Add-AzVMDataDisk -VM $VirtualMachine -Name 'DataDisk3' -Caching 'ReadOnly' -DiskSizeInGB 12 -Lun 2 -VhdUri $DataDiskVhdUri03 -CreateOption Empty ``` diff --git a/src/ConfidentialLedger/help/New-AzConfidentialLedger.md b/src/ConfidentialLedger/help/New-AzConfidentialLedger.md index e23c4c1caa98..e317c549233c 100644 --- a/src/ConfidentialLedger/help/New-AzConfidentialLedger.md +++ b/src/ConfidentialLedger/help/New-AzConfidentialLedger.md @@ -3,7 +3,7 @@ external help file: Module Name: Az.ConfidentialLedger online version: https://docs.microsoft.com/powershell/module/az.confidentialledger/new-azconfidentialledger schema: 2.0.0 ---- +--- # New-AzConfidentialLedger diff --git a/src/Storage/Storage.Management/help/Set-AzStorageFileContent.md b/src/Storage/Storage.Management/help/Set-AzStorageFileContent.md index cf7bfea9e985..6d32498dcbac 100644 --- a/src/Storage/Storage.Management/help/Set-AzStorageFileContent.md +++ b/src/Storage/Storage.Management/help/Set-AzStorageFileContent.md @@ -4,7 +4,7 @@ Module Name: Az.Storage ms.assetid: FA98E64B-D589-4653-9ACC-86573FAF4550 online version: https://docs.microsoft.com/powershell/module/az.storage/set-azstoragefilecontent schema: 2.0.0 ---- +--- # Set-AzStorageFileContent diff --git a/tools/StaticAnalysis/ExampleAnalyzer/AnalyzeRules/ParameterNameAndValue.psm1 b/tools/StaticAnalysis/ExampleAnalyzer/AnalyzeRules/ParameterNameAndValue.psm1 index fa01add92330..6a49b86dc8df 100644 --- a/tools/StaticAnalysis/ExampleAnalyzer/AnalyzeRules/ParameterNameAndValue.psm1 +++ b/tools/StaticAnalysis/ExampleAnalyzer/AnalyzeRules/ParameterNameAndValue.psm1 @@ -15,6 +15,8 @@ enum RuleNames { Mismatched_Parameter_Value_Type } +$global:UtilityOutputTypePair = @{"ConvertTo-Json" = [string]; "ConvertFrom-Json" = [hashtable]} + <# .SYNOPSIS Gets the actual name of the parameter, not alias. @@ -35,12 +37,25 @@ function Get-ParameterNameNotAlias { Gets the final actual value from ast. #> function Get-FinalVariableValue { - param([System.Management.Automation.Language.Ast]$CommandElementAst) - + param([System.Management.Automation.Language.Ast]$CommandElementAst, + [System.Management.Automation.Language.VariableExpressionAst]$VariableExpressionAst = $null) while ($true) { if ($null -ne $CommandElementAst.Expression) { $CommandElementAst = $CommandElementAst.Expression } + elseif ($null -ne $CommandElementAst.Left) { + if($CommandElementAst.Left -eq $VariableExpressionAst){ + if($CommandElementAst.Right -eq $VariableExpressionAst){ + $CommandElementAst = $null + } + else{ + $CommandElementAst = $CommandElementAst.Right + } + } + else{ + $CommandElementAst = $CommandElementAst.Left + } + } elseif ($null -ne $CommandElementAst.Target) { $CommandElementAst = $CommandElementAst.Target } @@ -48,7 +63,14 @@ function Get-FinalVariableValue { $CommandElementAst = $CommandElementAst.Pipeline } elseif ($null -ne $CommandElementAst.PipelineElements) { - $CommandElementAst = $CommandElementAst.PipelineElements[-1] + $LastElement = $CommandElementAst.PipelineElements[-1].Extent.Text + # If the LastElement contains "where" or "sort", then the type isnot changed. + if($LastElement -match "where" -or $LastElement -match "sort"){ + $CommandElementAst = $CommandElementAst.PipelineElements[0] + } + else{ + $CommandElementAst = $CommandElementAst.PipelineElements[-1] + } } elseif($null -ne $CommandElementAst.Elements){ $CommandElementAst = $CommandElementAst.Elements[0] @@ -98,13 +120,26 @@ function Get-RecoveredValueType{ } } else{ + if($Items[$j].Value -eq "new"){ + return $Type + } $Member = $Type.GetMembers() | Where-Object {$_.Name -eq $Items[$j]} + if($null -eq $Member){ + if($null -ne $Type.ImplementedInterfaces){ + for($i = 0; $i -lt $Type.ImplementedInterfaces.Length; $i++){ + $Member = $Type.ImplementedInterfaces[$i].GetMembers() | Where-Object {$_.Name -eq $Items[$j]} + if($null -ne $Member){ + break + } + } + } + if($null -eq $Member){ + return $null + } + } if($Member -is [array]){ $Member = $Member[0] } - if($null -eq $Member){ - return $null - } if($null -ne $Member.PropertyType){ $Type = $Member.PropertyType } @@ -119,6 +154,36 @@ function Get-RecoveredValueType{ return $Type } +<# + .SYNOPSIS + Measure whether the actual type matches the expected type. +#> +function Measure-IsTypeMatched{ + param ( + [System.Reflection.TypeInfo]$ExpectedType, + [System.Reflection.TypeInfo]$ActualType + ) + if($ActualType.IsArray) { + $ActualType = $ActualType.GetElementType() + } + if($ActualType.IsGenericType){ + $ActualType = $ActualType.GetGenericArguments()[0] + } + $Converter = [System.ComponentModel.TypeDescriptor]::GetConverter($ExpectedType) + if ($ActualType -eq $ExpectedType -or + $ActualType.GetInterfaces().Contains($ExpectedType) -or + $ExpectedType.GetInterfaces().Contains($ActualType) -or + $ActualType.IsSubclassOf($ExpectedType) -or + $Converter.CanConvertFrom($ActualType)) { + return $true + } + return $false +} + +<# + .SYNOPSIS + Gets the expression's actual value and type, if the parameter is assigned with a value. +#> function Get-AssignedParameterExpression { param ( [System.Management.Automation.CommandInfo]$GetCommand, @@ -134,7 +199,7 @@ function Get-AssignedParameterExpression { break } # Get the actual value - $CommandElement_Copy = Get-FinalVariableValue $global:AssignmentLeftAndRight.($CommandElement_Copy.Extent.Text) + $CommandElement_Copy = Get-FinalVariableValue $global:AssignmentLeftAndRight.($CommandElement_Copy.Extent.Text) $CommandElement_Copy if ($null -eq $CommandElement_Copy) { # Variable is not assigned with a value. # Unassigned_Variable @@ -142,16 +207,37 @@ function Get-AssignedParameterExpression { return $ExpressionToParameter } } + if($CommandElement_Copy.Extent.Text -match "foreach" -or $CommandElement_Copy.Extent.Text -match "select"){ + Write-Debug "The CommandElement contains 'foreach' or 'select'. This situation can not be handled now." + return $null + } + $ExpectedType = $GetCommand.Parameters.$ParameterNameNotAlias.ParameterType + if($CommandElement_Copy -is [System.Management.Automation.Language.HashtableAst]){ + # If ExpectedType is ValueType, then it cannot be created by Hashtable. + if($ExpectedType.IsValueType){ + # Mismatched_Parameter_Value_Type + $ExpressionToParameter = "$($CommandElement.Extent.Text)-#-$ExpectedType, created by hashtable but is value type." + return $ExpressionToParameter + } + return $null + } + while ($ExpectedType.IsArray) { + $ExpectedType = $ExpectedType.GetElementType() + } + if($ExpectedType.IsGenericType){ + $ExpectedType = $ExpectedType.GetGenericArguments()[0] + } if ($CommandElement_Copy -is [System.Management.Automation.Language.CommandAst]) { # Value is an command # If the value is created by "New-Object", then get the type behind "New-Object". if($CommandElement_Copy.CommandElements[0].Extent.Text -eq "New-Object"){ if($CommandElement_Copy.CommandElements[1].Extent.Text -eq "-TypeName"){ - $OutputType = $CommandElement_Copy.CommandElements[2].Extent.Text -as [Type] + $TypeName = $CommandElement_Copy.CommandElements[2].Extent.Text -replace "`"" } else{ - $OutputType = $CommandElement_Copy.CommandElements[1].Extent.Text -as [Type] + $TypeName = $CommandElement_Copy.CommandElements[1].Extent.Text } + $OutputType = $TypeName -as [Type] $OutputTypes = @() + $OutputType } else{ @@ -162,10 +248,16 @@ function Get-AssignedParameterExpression { return $null } $OutputTypes = @() - $j = 0 - while($GetElementCommand.OutputType[$j]){ - $OutputTypes += $GetElementCommand.OutputType[$j].Type - $j++ + if($global:UtilityOutputTypePair.ContainsKey($GetElementCommand.Name)){ + $OutputType = $global:UtilityOutputTypePair.($GetElementCommand.Name) + $OutputTypes += $OutputType + } + else{ + $j = 0 + while($GetElementCommand.OutputType[$j]){ + $OutputTypes += $GetElementCommand.OutputType[$j].Type + $j++ + } } } $flag = $true @@ -174,63 +266,43 @@ function Get-AssignedParameterExpression { $ReturnType = $OutputTypes[$j] $j++ $ActualType = Get-RecoveredValueType $CommandElement $ReturnType - $ExpectedType = $GetCommand.Parameters.$ParameterNameNotAlias.ParameterType if($null -eq $ActualType){ Continue } - if ($ExpectedType.IsArray) { - $ExpectedType = $ExpectedType.GetElementType() - } - if($ActualType.IsArray) { - $ActualType = $ActualType.GetElementType() - } - if($ActualType.IsGenericType){ - $ActualType = $ActualType.GetGenericArguments()[0] - } - if($ExpectedType.IsGenericType){ - $ExpectedType = $ExpectedType.GetGenericArguments()[0] - } - if ($ActualType -eq $ExpectedType -or $ActualType -is $ExpectedType -or - $ActualType.GetInterfaces().Contains($ExpectedType) -or $ExpectedType.GetInterfaces().Contains($ActualType)) { + if(Measure-IsTypeMatched $ExpectedType $ActualType){ $flag = $false + break } } if($flag){ # Mismatched_Parameter_Value_Type - $ExpressionToParameter = "$($CommandElement.Extent.Text)-#-$ExpectedType" + $ExpressionToParameter = "$($CommandElement.Extent.Text)-#-$ExpectedType. Now the type is $ActualType.(Command)" return $ExpressionToParameter } - } - elseif($CommandElement_Copy -is [System.Management.Automation.Language.HashtableAst]){ - # If ExpectedType is ValueType, then it cannot be created by Hashtable. - if($ExpectedType.IsValueType){ + elseif($CommandElement_Copy -is [System.Management.Automation.Language.TypeExpressionAst] -or + $CommandElement_Copy -is [System.Management.Automation.Language.TypeConstraintAst]){ + $ReturnType = $CommandElement_Copy.TypeName.ToString() -as [Type] + $ActualType = Get-RecoveredValueType $CommandElement $ReturnType + if (!(Measure-IsTypeMatched $ExpectedType $ActualType)) { # Mismatched_Parameter_Value_Type - $ExpressionToParameter = "$($CommandElement.Extent.Text)-#-$ExpectedType" + $ExpressionToParameter = "$($CommandElement.Extent.Text)-#-$ExpectedType. Now the type is $ActualType.(Type)" return $ExpressionToParameter } } elseif($CommandElement_Copy -is [System.Management.Automation.Language.ExpressionAst]) { - # Value is a constant expression - $ExpectedType = $GetCommand.Parameters.$ParameterNameNotAlias.ParameterType + # Value is a constant expression $ConvertedObject = $CommandElement_Copy.Extent.text -as $ExpectedType - $StaticType = $CommandElement_Copy.StaticType - if($ExpectedType.IsGenericType){ - $ExpectedType = $ExpectedType.GetGenericArguments()[0] - } - if($StaticType.IsGenericType){ - $StaticType = $StaticType.GetGenericArguments()[0] - } - if ($ExpectedType.IsArray){ - $ExpectedType = $ExpectedType.GetElementType() - } - if($StaticType.IsArray){ - $StaticType = $StaticType.GetElementType() + if($null -eq $ConvertedObject){ + if($null -ne (Get-Variable | Where-Object {$_.Name -eq $CommandElement_Copy.VariablePath})){ + $value = (Get-Variable | Where-Object {$_.Name -eq $CommandElement_Copy.VariablePath}).Value + } + $ConvertedObject = $value -as $ExpectedType } - if ($StaticType -ne $ExpectedType -and $null -eq $ConvertedObject -and - !$StaticType.GetInterfaces().Contains($ExpectedType) -and !$ExpectedType.GetInterfaces().Contains($StaticType)) { + $StaticType = $CommandElement_Copy.StaticType + if (!(Measure-IsTypeMatched $ExpectedType $StaticType) -and $null -eq $ConvertedObject) { # Mismatched_Parameter_Value_Type - $ExpressionToParameter = "$($CommandElement.Extent.Text)-#-$ExpectedType" + $ExpressionToParameter = "$($CommandElement.Extent.Text)-#-$ExpectedType. Now the type is $StaticType.(Static)" return $ExpressionToParameter } } @@ -272,7 +344,12 @@ function Measure-ParameterNameAndValue { if ($Ast -is [System.Management.Automation.Language.AssignmentStatementAst]) { [System.Management.Automation.Language.AssignmentStatementAst]$AssignmentStatementAst = $Ast - $global:AssignmentLeftAndRight.($AssignmentStatementAst.Left.Extent.Text) = $AssignmentStatementAst.Right + if($AssignmentStatementAst.Left -is [System.Management.Automation.Language.ConvertExpressionAst]){ + $global:AssignmentLeftAndRight.($AssignmentStatementAst.Left.Child.Extent.Text) = $AssignmentStatementAst.Left.Type + } + elseif($AssignmentStatementAst.Left -is [System.Management.Automation.Language.VariableExpressionAst]){ + $global:AssignmentLeftAndRight.($AssignmentStatementAst.Left.Extent.Text) = $AssignmentStatementAst.Right + } } if ($Ast -is [System.Management.Automation.Language.CommandElementAst] -and $Ast.Parent -is [System.Management.Automation.Language.CommandAst]) { diff --git a/tools/StaticAnalysis/ExampleAnalyzer/utils.ps1 b/tools/StaticAnalysis/ExampleAnalyzer/utils.ps1 index f8397bda47bb..9973344b66a0 100644 --- a/tools/StaticAnalysis/ExampleAnalyzer/utils.ps1 +++ b/tools/StaticAnalysis/ExampleAnalyzer/utils.ps1 @@ -75,16 +75,21 @@ function Get-ExamplesDetailsFromMd { $indexOfExamples = $fileContent.IndexOf($EXAMPLES_HEADING) $indexOfParameters = $fileContent.IndexOf($PARAMETERS_HEADING) - $exampleNumber = 0 + $exampleNumber = -1 $examplesProperties = @() $examplesContent = $fileContent.Substring($indexOfExamples, $indexOfParameters - $indexOfExamples) $examplesTitles = ($examplesContent | Select-String -Pattern $SINGLE_EXAMPLE_TITLE_HEADING_REGEX -AllMatches).Matches $examplesContentWithoutTitle = $examplesContent -split $SINGLE_EXAMPLE_TITLE_HEADING_REGEX | Select-Object -Skip 1 foreach ($exampleContent in $examplesContentWithoutTitle) { + $exampleNumber++ # Skip the autogenerated example if($exampleContent -match "\(autogenerated\)"){ continue } + # Skip the example whose output can not be splitted from code + if($exampleContent -match ""){ + continue + } $exampleTitle = ($examplesTitles[$exampleNumber].Value -split $SINGLE_EXAMPLE_HEADING_REGEX)[1].Trim() $exampleCodes = @() $exampleOutputs = @() @@ -323,26 +328,28 @@ function Measure-SectionMissingAndOutputScript { $examplesDetails = Get-ExamplesDetailsFromMd $MarkdownPath # If no examples if ($examplesDetails.Count -eq 0) { - $missingExampleTitle++ - $missingExampleCode++ - $missingExampleOutput++ - $missingExampleDescription++ - $result = [AnalysisOutput]@{ - Module = $Module - Cmdlet = $Cmdlet - Example = "" - Description = "Example is missing." - RuleName = "MissingExample" - Severity = $missingSeverity - Extent = "$Module\help\$Cmdlet.md" - ProblemID = 5042 - Remediation = "Add Example. Remove any placeholders." + if($fileContent -notmatch "\(autogenerated\)" -and $fileContent -notmatch ""){ + $missingExampleTitle++ + $missingExampleCode++ + $missingExampleOutput++ + $missingExampleDescription++ + $result = [AnalysisOutput]@{ + Module = $Module + Cmdlet = $Cmdlet + Example = "" + Description = "Example is missing." + RuleName = "MissingExample" + Severity = $missingSeverity + Extent = "$Module\help\$Cmdlet.md" + ProblemID = 5042 + Remediation = "Add Example. Remove any placeholders." + } + $results += $result } - $results += $result } else { foreach ($exampleDetails in $examplesDetails) { - $exampleNumber++ + $exampleNumber = $exampleDetails.Num $_missingExampleTitle = ($exampleDetails.Title | Select-String -Pattern "{{[A-Za-z ]*}}").Count $_missingExampleCode = ($exampleDetails.Codes | Select-String -Pattern "{{[A-Za-z ]*}}").Count $_missingExampleOutput = ($exampleDetails.Outputs | Select-String -Pattern "{{[A-Za-z ]*}}").Count @@ -435,7 +442,7 @@ function Measure-SectionMissingAndOutputScript { RuleName = "NeedDeleting" Severity = $missingSeverity Extent = "$Module\help\$Cmdlet.md" - ProblemID = 5051 + ProblemID = 5052 Remediation = "Delete the prompt of example." } $results += $result diff --git a/tools/StaticAnalysis/Exceptions/Az.Accounts/ExampleIssues.csv b/tools/StaticAnalysis/Exceptions/Az.Accounts/ExampleIssues.csv new file mode 100644 index 000000000000..67c001ce7aca --- /dev/null +++ b/tools/StaticAnalysis/Exceptions/Az.Accounts/ExampleIssues.csv @@ -0,0 +1,8 @@ +"Module","Cmdlet","Example","RuleName","ProblemID","Severity","Description","Extent","Remediation" +"Accounts","Disconnect-AzAccount","2","Unbinded_Expression","5014","2","Get-AzContext 'Work' is not explicitly assigned to a parameter.","'Work'","Assign 'Work' explicitly to the parameter." +"Accounts","Remove-AzContext","1","Invalid_Parameter_Name","5011","2","Remove-AzContext -Name is not a valid parameter name.","-Name","Check validity of the parameter Name." +"Accounts","Rename-AzContext","1","Invalid_Parameter_Name","5011","2","Rename-AzContext -SourceName is not a valid parameter name.","-SourceName","Check validity of the parameter SourceName." +"Accounts","Rename-AzContext","1","Invalid_Parameter_Name","5011","2","Rename-AzContext -TargetName is not a valid parameter name.","-TargetName","Check validity of the parameter TargetName." +"Accounts","Rename-AzContext","2","Unbinded_Expression","5014","2","Rename-AzContext 'My context' is not explicitly assigned to a parameter.","'My context'","Assign 'My context' explicitly to the parameter." +"Accounts","Rename-AzContext","2","Unbinded_Expression","5014","2","Rename-AzContext 'Work' is not explicitly assigned to a parameter.","'Work'","Assign 'Work' explicitly to the parameter." +"Accounts","Select-AzContext","1","Unbinded_Expression","5014","2","Select-AzContext 'Work' is not explicitly assigned to a parameter.","'Work'","Assign 'Work' explicitly to the parameter." \ No newline at end of file