Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
The table of contents is too big for display.
Diff view
Diff view
  •  
  •  
  •  
23 changes: 23 additions & 0 deletions powershell/misc/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@

# Type model generation

Type information about .NET and PowerShell SDK methods are obtained by generating data extension files that populate the `typeModel` extensible predicate.

The type models are located here: https://github.com/microsoft/codeql/blob/main/powershell/ql/lib/semmle/code/powershell/frameworks/

Follow the steps below in order to generate new type models:
1. Join the `MicrosoftDocs` organisation to ensure that you can access https://github.com/MicrosoftDocs/powershell-docs-sdk-dotnet/tree/main/dotnet/xml (if you haven't already).
2.
Run the following commands

```
# Clone dotnet/dotnet-api-docs
git clone https://github.com/dotnet/dotnet-api-docs
# Clone MicrosoftDocs/powershell-docs-sdk-dotnet
git clone [email protected]:MicrosoftDocs/powershell-docs-sdk-dotnet.git
# Generate data extensions
python3 misc/typemodelgen.py dotnet-api-docs/xml/ powershell-docs-sdk-dotnet/dotnet/xml
```
This will generate 600+ folders that need to be copied into https://github.com/microsoft/codeql/blob/main/powershell/ql/lib/semmle/code/powershell/frameworks/.

Note: Care must be taken to ensure that manually modified versions aren't overwritten.
176 changes: 176 additions & 0 deletions powershell/misc/typemodelgen.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,176 @@
import xml.etree.ElementTree as ET
from pathlib import Path
import sys
import os
from collections import defaultdict


def fixup(t):
"""Sometimes the docs specify a type that doesn't align with what
PowerShell reports. This function fixes up those types so that it aligns with PowerShell.
"""
if t.startswith("System.ReadOnlySpan<"):
return "System.String"
return t


def isStatic(member):
"""Returns True if the member is static, False otherwise."""
for child in member:
if child.tag == "MemberSignature" and "static" in child.attrib["Value"]:
return True
return False


def isA(x):
"""Returns True if member is an `x`."""
for child in member:
if child.tag == "MemberType" and child.text == x:
return True
return False


def isMethod(member):
"""Returns True if the member is a method, False otherwise."""
return isA(member, "Method")


def isField(member):
"""Returns True if the member is a field, False otherwise."""
return isA(member, "Field")


def isProperty(member):
"""Returns True if the member is a property, False otherwise."""
return isA(member, "Property")


def isEvent(member):
"""Returns True if the member is an event, False otherwise."""
return isA(member, "Event")


def isAttachedProperty(member):
"""Returns True if the member is an attached property, False otherwise."""
return isA(member, "AttachedProperty")


def isAttachedEvent(member):
"""Returns True if the member is an attached event, False otherwise."""
return isA(member, "AttachedEvent")


def isConstructor(member):
"""Returns True if the member is a constructor, False otherwise."""
return isA(member, "Constructor")


# A map from filenames to a set of type models to be stored in the file
summaries = defaultdict(set)


def generateTypeModels(arg):
"""Generates type models for the given XML file."""
folder_path = Path(arg)

for file_path in folder_path.rglob("*"):
try:
if not file_path.name.endswith(".xml"):
continue

if not file_path.is_file():
continue

tree = ET.parse(str(file_path))
root = tree.getroot()
if not root.tag == "Type":
continue

thisType = root.attrib["FullName"]

if "`" in file_path.stem or "+" in file_path.stem:
continue # Skip generics (and nested types?) for now

folderName = file_path.parent.name.replace(".", "")
filename = folderName + "/model.yml"
s = set()
for elem in root.findall(".//Members/Member"):
name = elem.attrib["MemberName"]
if name == ".ctor":
continue

staticMarker = ""
if isStatic(elem):
staticMarker = "!"

startSelectorMarker = ""
endSelectorMarker = ""
if isField(elem):
startSelectorMarker = "Field"
endSelectorMarker = ""
if isProperty(elem):
startSelectorMarker = "Property"
endSelectorMarker = ""
if isMethod(elem):
startSelectorMarker = "Method"
endSelectorMarker = ".ReturnValue"

if isEvent(elem):
continue # What are these?
if isAttachedProperty(elem):
continue # What are these?
if isAttachedEvent(elem):
continue # What are these?
if isConstructor(elem):
continue # No need to model the type information for constructors
if startSelectorMarker == "":
print(f"Error: Unknown type for {thisType}.{name}")
continue

if elem.find(".//ReturnValue/ReturnType") is None:
print(f"Error: {name} has no return type!")
continue

returnType = elem.find(".//ReturnValue/ReturnType").text
if returnType == "System.Void":
continue # Don't generate type summaries for void methods
s.add(
f' - ["{fixup(returnType)}", "{thisType + staticMarker}", "{startSelectorMarker}[{name}]{endSelectorMarker}"]\n'
)

summaries[filename].update(s)

except ET.ParseError as e:
print(f"Error parsing XML: {e}")
except Exception as e:
print(f"An error occurred: {repr(e)}")


def writeModels():
"""Writes the type models to disk."""
for filename, s in summaries.items():
if len(s) == 0:
continue
os.makedirs(os.path.dirname(filename), exist_ok=True)
with open(filename, "x") as file:
file.write("extensions:\n")
file.write(" - addsTo:\n")
file.write(" pack: microsoft-sdl/powershell-all\n")
file.write(" extensible: typeModel\n")
file.write(" data:\n")
for summary in s:
for x in summary:
file.write(x)


if __name__ == "__main__":
if len(sys.argv) < 2:
print("Usage: python parse_xml.py <xml_file1> <xml_file2> ... <xml_fileN>")
sys.exit(1)

for arg in sys.argv[1:]:
print(f"Processing {arg}...")
generateTypeModels(arg)

print("Writing models...")
writeModels()
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
extensions:
- addsTo:
pack: microsoft-sdl/powershell-all
extensible: typeModel
data:
- ["System.String", "Accessibility.IAccessible", "Property[accHelp]"]
- ["System.Object", "Accessibility.IAccessible", "Method[accHitTest].ReturnValue"]
- ["System.Int32", "Accessibility._RemotableHandle", "Field[fContext]"]
- ["System.Int32", "Accessibility.IAccessible", "Property[accChildCount]"]
- ["System.Object", "Accessibility.IAccessible", "Property[accState]"]
- ["Accessibility.AnnoScope", "Accessibility.AnnoScope!", "Field[ANNO_THIS]"]
- ["System.Int32", "Accessibility.__MIDL_IWinTypes_0009", "Field[hRemote]"]
- ["System.Object", "Accessibility.IAccessible", "Property[accParent]"]
- ["System.Object", "Accessibility.IAccessible", "Property[accRole]"]
- ["System.Object", "Accessibility.IAccessible", "Property[accChild]"]
- ["System.String", "Accessibility.IAccessible", "Property[accKeyboardShortcut]"]
- ["System.Object", "Accessibility.IAccessible", "Property[accSelection]"]
- ["System.Int32", "Accessibility.IAccessible", "Property[accHelpTopic]"]
- ["System.String", "Accessibility.IAccessible", "Property[accDescription]"]
- ["System.String", "Accessibility.IAccessible", "Property[accDefaultAction]"]
- ["System.Object", "Accessibility.IAccessible", "Property[accFocus]"]
- ["Accessibility.__MIDL_IWinTypes_0009", "Accessibility._RemotableHandle", "Field[u]"]
- ["System.String", "Accessibility.IAccessible", "Property[accValue]"]
- ["System.Int32", "Accessibility.__MIDL_IWinTypes_0009", "Field[hInproc]"]
- ["System.String", "Accessibility.IAccessible", "Property[accName]"]
- ["Accessibility.AnnoScope", "Accessibility.AnnoScope!", "Field[ANNO_CONTAINER]"]
- ["System.Object", "Accessibility.IAccessible", "Method[accNavigate].ReturnValue"]
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
extensions:
- addsTo:
pack: microsoft-sdl/powershell-all
extensible: typeModel
data:
- ["System.Int32", "IEHost.Execute.IEExecuteRemote", "Method[ExecuteAsDll].ReturnValue"]
- ["System.IO.Stream", "IEHost.Execute.IEExecuteRemote", "Property[Exception]"]
- ["System.Object", "IEHost.Execute.IEExecuteRemote", "Method[InitializeLifetimeService].ReturnValue"]
- ["System.Int32", "IEHost.Execute.IEExecuteRemote", "Method[ExecuteAsAssembly].ReturnValue"]
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
extensions:
- addsTo:
pack: microsoft-sdl/powershell-all
extensible: typeModel
data:
- ["System.Boolean", "Microsoft.Activities.Build.WorkflowBuildMessageTask", "Method[Execute].ReturnValue"]
- ["System.String", "Microsoft.Activities.Build.WorkflowBuildMessageTask", "Property[ResourceName]"]
- ["System.String", "Microsoft.Activities.Build.WorkflowBuildMessageTask", "Property[MessageType]"]
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
extensions:
- addsTo:
pack: microsoft-sdl/powershell-all
extensible: typeModel
data:
- ["System.Boolean", "Microsoft.Activities.Build.Debugger.DebugBuildExtension", "Method[Execute].ReturnValue"]
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
extensions:
- addsTo:
pack: microsoft-sdl/powershell-all
extensible: typeModel
data:
- ["System.Boolean", "Microsoft.Activities.Build.Expressions.ExpressionsBuildExtension", "Method[Execute].ReturnValue"]
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
extensions:
- addsTo:
pack: microsoft-sdl/powershell-all
extensible: typeModel
data:
- ["System.Boolean", "Microsoft.Activities.Build.Validation.ReportDeferredValidationErrorsTask", "Method[Execute].ReturnValue"]
- ["System.String", "Microsoft.Activities.Build.Validation.DeferredValidationTask", "Property[DeferredValidationErrorsFilePath]"]
- ["System.String", "Microsoft.Activities.Build.Validation.ReportDeferredValidationErrorsTask", "Property[DeferredValidationErrorsFilePath]"]
- ["System.Boolean", "Microsoft.Activities.Build.Validation.DeferredValidationTask", "Method[Execute].ReturnValue"]
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
extensions:
- addsTo:
pack: microsoft-sdl/powershell-all
extensible: typeModel
data:
- ["System.Int32", "Microsoft.Aspnet.Snapin.IExtendPropertySheet2", "Method[CreatePropertyPages].ReturnValue"]
- ["Microsoft.Aspnet.Snapin.MMC_CONTROL_TYPE", "Microsoft.Aspnet.Snapin.MMC_CONTROL_TYPE!", "Field[TOOLBAR]"]
- ["System.Int32", "Microsoft.Aspnet.Snapin.SCOPEDATAITEM", "Field[mask]"]
- ["System.Int32", "Microsoft.Aspnet.Snapin.IDataObject", "Method[EnumDAdvise].ReturnValue"]
- ["System.Int32", "Microsoft.Aspnet.Snapin.SCOPEDATAITEM", "Field[cChildren]"]
- ["System.Int32", "Microsoft.Aspnet.Snapin.SCOPEDATAITEM", "Field[lParam]"]
- ["System.Int32", "Microsoft.Aspnet.Snapin.IExtendPropertySheet", "Method[QueryPagesFor].ReturnValue"]
- ["System.Int32", "Microsoft.Aspnet.Snapin.SCOPEDATAITEM", "Field[relativeID]"]
- ["System.Int32", "Microsoft.Aspnet.Snapin.IDataObject", "Method[DAdvise].ReturnValue"]
- ["System.Int32", "Microsoft.Aspnet.Snapin.IDataObject", "Method[EnumFormatEtc].ReturnValue"]
- ["System.Int32", "Microsoft.Aspnet.Snapin.IExtendPropertySheet2", "Method[GetWatermarks].ReturnValue"]
- ["System.Int32", "Microsoft.Aspnet.Snapin.IContextMenuCallback", "Method[AddItem].ReturnValue"]
- ["System.Int32", "Microsoft.Aspnet.Snapin.SCOPEDATAITEM", "Field[nOpenImage]"]
- ["System.Int32", "Microsoft.Aspnet.Snapin.IDataObject", "Method[QueryGetData].ReturnValue"]
- ["System.Int32", "Microsoft.Aspnet.Snapin.SCOPEDATAITEM", "Field[ID]"]
- ["System.IntPtr", "Microsoft.Aspnet.Snapin.AspNetManagementUtility!", "Method[GetActiveWindow].ReturnValue"]
- ["Microsoft.Aspnet.Snapin.MMC_CONTROL_TYPE", "Microsoft.Aspnet.Snapin.MMC_CONTROL_TYPE!", "Field[COMBOBOXBAR]"]
- ["System.Int32", "Microsoft.Aspnet.Snapin.SCOPEDATAITEM", "Field[nState]"]
- ["System.Int32", "Microsoft.Aspnet.Snapin.IDataObject", "Method[SetData].ReturnValue"]
- ["System.Int32", "Microsoft.Aspnet.Snapin.IDataObject", "Method[GetData].ReturnValue"]
- ["System.Int32", "Microsoft.Aspnet.Snapin.IExtendPropertySheet", "Method[CreatePropertyPages].ReturnValue"]
- ["System.IntPtr", "Microsoft.Aspnet.Snapin.SCOPEDATAITEM", "Field[displayname]"]
- ["System.Int32", "Microsoft.Aspnet.Snapin.IDataObject", "Method[DUnadvise].ReturnValue"]
- ["System.Int32", "Microsoft.Aspnet.Snapin.SCOPEDATAITEM", "Field[nImage]"]
- ["Microsoft.Aspnet.Snapin.MMC_CONTROL_TYPE", "Microsoft.Aspnet.Snapin.MMC_CONTROL_TYPE!", "Field[MENUBUTTON]"]
- ["System.Int32", "Microsoft.Aspnet.Snapin.IDataObject", "Method[GetDataHere].ReturnValue"]
- ["System.Int32", "Microsoft.Aspnet.Snapin.IExtendPropertySheet2", "Method[QueryPagesFor].ReturnValue"]
- ["System.Int32", "Microsoft.Aspnet.Snapin.IDataObject", "Method[GetCanonicalFormatEtc].ReturnValue"]
- ["System.Int32", "Microsoft.Aspnet.Snapin.AspNetManagementUtility!", "Method[MessageBox].ReturnValue"]
Loading