Repository navigation
Set‑ShpToolPolicy
Scopes what the file and shell tools may reach, for the current session.
Set-ShpToolPolicy [[-Rule] <String[]>] [-TrustProfile <String>] [-WhatIf]
[-Confirm] [<CommonParameters>]
Set-ShpToolPolicy -Path <String> [-TrustProfile <String>] [-WhatIf]
[-Confirm] [<CommonParameters>]
Defines an allow/deny rule set for the unsandboxed tools, so an unattended run can be given the access it actually needs instead of the caller's entire filesystem and shell.
Until this is called there is no policy and every tool call is permitted, exactly as before. Once it is called the model is denied by default: an operation is allowed only when a rule covers it. That migration is deliberate - deny-by-default is the correct posture, and making it conditional on a policy existing keeps every current caller working.
Rules are written as Kind(argument), after the GitHub Copilot CLI:
Read(<path>) read_file, list_directory, glob_files, grep_files and edit_file
Write(<path>) write_file, edit_file and create_directory
Shell(<command prefix>) run_command
Url(<address prefix>) fetch_url
Mcp(<alias>/<tool>) one attached MCP server's tools
Tool(<name>) every other named tool, including user tools
edit_file requires both Read and Write rules covering the same resolved path, because its match results reveal content even for a no-op edit. A deny in either kind refuses the edit. write_file and create_directory still require only Write access.
A leading ! makes a rule a deny, and any matching deny beats every matching allow - so 'Read(./)' with '!Read(./.git/)' reads the tree except its history. That precedence is the same for every kind.
COVERAGE IS STAGED. Read, Write and Shell are enforced by every policy, as they always were. Url, Mcp and Tool are enforced only when the policy actually uses that kind, or when -TrustProfile RestrictedUnattended asks for all of them. A policy written before those kinds existed therefore keeps working unchanged: adding a kind must never retroactively deny a tool the caller's rules never mentioned. Get-ShpToolPolicy reports the resolved Coverage so an unattended run can assert its own posture.
Paths accept * for one segment and ** for any depth, and are matched on
the absolute, link-resolved path rather than the string the model
supplied, so neither a .. segment nor a directory link escapes an
allowed root.
A path with no wildcard matches that one item only.
Shell rules match whole leading tokens, so 'Shell(git status)' allows 'git status --short' but not 'git push', and never matches 'gitleaks'. A command containing a shell metacharacter is refused whatever the rules say, because 'git status; curl ...' would otherwise pass a rule that only ever meant 'git status'. A Shell rule constrains WHICH program runs, not what it does: it is a coarse control, not a sandbox.
Url rules take the same wildcards and are matched on the normalised address - lower-cased scheme and punycode host, default port dropped, dot segments collapsed, query and fragment ignored - so one target has one spelling. An address carrying userinfo credentials is refused outright. A Url rule decides WHICH address may be fetched; the private-network guard on fetch_url is a separate control that still applies.
Mcp rules name the server alias and the tool as the server knows it, never the namespaced name the model sees, so a model cannot reach a different server by inventing a name. 'Mcp(files/)' and the shorthand 'Mcp(files)' cover one server; 'Mcp()' covers every attached server.
Tool rules match a tool name exactly, with * as a wildcard. They cover everything the other kinds do not: ask_user, load_skill, load_instruction, manage_todo_list, search_tools and every user tool registered with Register-ShpTool.
The policy is session state, not a per-call parameter, on purpose. A reach that changed between iterations of one unattended loop would make the weakest call in the loop define the blast radius, and there would be no single place to audit. Invoke-ShpBatch replays it into every worker.
Parsing fails closed. A rule that cannot be understood throws and the previous policy is left in place, so a typo can never widen what the model may reach.
Set-ShpToolPolicy -Rule @('Read(./**)', '!Read(./.git/**)', 'Write(./out/**)', 'Shell(git status)')
Lets the model read the tree except its git history, write only under out/, and run only 'git status'.
Set-ShpToolPolicy -Rule @('Read(./src/**)', 'Write(./src/**)')
Lets the model inspect and edit files under src. A Write rule alone permits write_file, but not edit_file.
Set-ShpToolPolicy -TrustProfile RestrictedUnattended -Rule @('Read(./src/**)', 'Url(https://docs.example.com/**)')
The restricted unattended posture: reads under src and fetches under one documentation site, and denies every other tool, server and address.
Set-ShpToolPolicy -Path ./triage-policy.txt
Loads the same rules from a file you have chosen to trust.
A file to read the rules from, one per line; blank lines and lines starting with # are ignored. The file is read only because you named it here - no policy file is ever discovered automatically, because a file picked up from the working directory would let whoever can write there widen the model's reach.
Type: String
Parameter Sets: Path
Aliases:
Required: True
Position: Named
Default value: None
Accept pipeline input: False
Accept wildcard characters: FalseThe rules to apply, replacing any current policy.
Type: String[]
Parameter Sets: Rule
Aliases:
Required: False
Position: 1
Default value: None
Accept pipeline input: False
Accept wildcard characters: FalseThe posture the policy starts from. Legacy is the default and enforces Read, Write and Shell plus whichever further kinds the rules use. RestrictedUnattended enforces every kind, so a tool call runs only when a rule grants it; it seeds allow rules for manage_todo_list and search_tools, which read and record nothing outside the turn, and denies everything else until you add rules. It is never applied implicitly - an existing caller keeps the Legacy posture unless this parameter names another.
Type: String
Parameter Sets: (All)
Aliases:
Required: False
Position: Named
Default value: Legacy
Accept pipeline input: False
Accept wildcard characters: FalsePrompts you for confirmation before running the cmdlet.
Type: SwitchParameter
Parameter Sets: (All)
Aliases: cf
Required: False
Position: Named
Default value: None
Accept pipeline input: False
Accept wildcard characters: FalseShows what would happen if the cmdlet runs. The cmdlet is not run.
Type: SwitchParameter
Parameter Sets: (All)
Aliases: wi
Required: False
Position: Named
Default value: None
Accept pipeline input: False
Accept wildcard characters: FalseThis cmdlet supports the common parameters: -Debug, -ErrorAction, -ErrorVariable, -InformationAction, -InformationVariable, -OutVariable, -OutBuffer, -PipelineVariable, -Verbose, -WarningAction, and -WarningVariable. For more information, see about_CommonParameters.
- Clear-ShpChat
- Clear-ShpContext
- Clear-ShpRedactionPolicy
- Clear-ShpToolPolicy
- Clear-ShpUsage
- Compress-ShpChat
- ConvertTo-ShpAnnotation
- ConvertTo-ShpOtelTrace
- ConvertTo-ShpTokenCount
- Get-ShpChat
- Get-ShpChatCheckpoint
- Get-ShpContext
- Get-ShpContextReport
- Get-ShpCosineSimilarity
- Get-ShpCostEstimate
- Get-ShpDefault
- Get-ShpMcpServer
- Get-ShpModel
- Get-ShpModelName
- Get-ShpRedactionPolicy
- Get-ShpTool
- Get-ShpToolPolicy
- Get-ShpUsage
- Initialize-Shp
- Invoke-Shp
- Invoke-ShpBatch
- Invoke-ShpEval
- Invoke-ShpSubagent
- Register-ShpMcpServer
- Register-ShpTool
- Request-ShpEmbedding
- Resolve-ShpError
- Restore-ShpChat
- Save-ShpChat
- Select-ShpModel
- Set-ShpContext
- Set-ShpRedactionPolicy
- Set-ShpToolPolicy
- Start-ShpChat
- Test-ShpCiReadiness
- Unregister-ShpMcpServer
- Unregister-ShpTool