Initial commit
This commit is contained in:
15
.claude-plugin/plugin.json
Normal file
15
.claude-plugin/plugin.json
Normal file
@@ -0,0 +1,15 @@
|
|||||||
|
{
|
||||||
|
"name": "powershell-master",
|
||||||
|
"description": "Complete PowerShell 7.5/7.6 expertise system across ALL platforms (Windows/Linux/macOS) with 2025 breaking changes coverage and shell detection. PROACTIVELY activate for: (1) ANY PowerShell task (scripts/modules/cmdlets), (2) PowerShell 7.5/7.6 new features (ConvertTo-CliXml, Test-Path time filtering, PSResourceGet), (3) 2025 migrations (MSOnline/AzureAD retirement, PowerShell 2.0 removal, WMIC replacement), (4) Modern security (JEA, WDAC, Constrained Language Mode), (5) CI/CD automation (GitHub Actions/Azure DevOps/Bitbucket), (6) PSResourceGet package management (2x faster than PowerShellGet), (7) Azure Az 14.5.0 with zone redundancy, (8) Microsoft.Graph 2.32.0 automation, (9) Cross-platform scripting with .NET 9 performance, (10) Shell detection and cross-shell compatibility (PowerShell vs Git Bash/MSYS2). Provides: PowerShell 7.5.4 stable / 7.6 preview features, 2025 breaking changes guidance, MSOnline/AzureAD to Microsoft.Graph migration paths, PSResourceGet adoption patterns, latest security best practices (JEA, WDAC), popular module expertise (Az 14.5.0, Microsoft.Graph 2.32.0, PnP, AWS Tools), shell detection on Windows (PowerShell vs Git Bash), path conversion knowledge, and production-ready 2025 automation patterns.",
|
||||||
|
"version": "1.5.0",
|
||||||
|
"author": {
|
||||||
|
"name": "Josiah Siegel",
|
||||||
|
"email": "JosiahSiegel@users.noreply.github.com"
|
||||||
|
},
|
||||||
|
"skills": [
|
||||||
|
"./skills"
|
||||||
|
],
|
||||||
|
"agents": [
|
||||||
|
"./agents"
|
||||||
|
]
|
||||||
|
}
|
||||||
3
README.md
Normal file
3
README.md
Normal file
@@ -0,0 +1,3 @@
|
|||||||
|
# powershell-master
|
||||||
|
|
||||||
|
Complete PowerShell 7.5/7.6 expertise system across ALL platforms (Windows/Linux/macOS) with 2025 breaking changes coverage and shell detection. PROACTIVELY activate for: (1) ANY PowerShell task (scripts/modules/cmdlets), (2) PowerShell 7.5/7.6 new features (ConvertTo-CliXml, Test-Path time filtering, PSResourceGet), (3) 2025 migrations (MSOnline/AzureAD retirement, PowerShell 2.0 removal, WMIC replacement), (4) Modern security (JEA, WDAC, Constrained Language Mode), (5) CI/CD automation (GitHub Actions/Azure DevOps/Bitbucket), (6) PSResourceGet package management (2x faster than PowerShellGet), (7) Azure Az 14.5.0 with zone redundancy, (8) Microsoft.Graph 2.32.0 automation, (9) Cross-platform scripting with .NET 9 performance, (10) Shell detection and cross-shell compatibility (PowerShell vs Git Bash/MSYS2). Provides: PowerShell 7.5.4 stable / 7.6 preview features, 2025 breaking changes guidance, MSOnline/AzureAD to Microsoft.Graph migration paths, PSResourceGet adoption patterns, latest security best practices (JEA, WDAC), popular module expertise (Az 14.5.0, Microsoft.Graph 2.32.0, PnP, AWS Tools), shell detection on Windows (PowerShell vs Git Bash), path conversion knowledge, and production-ready 2025 automation patterns.
|
||||||
356
agents/powershell-expert.md
Normal file
356
agents/powershell-expert.md
Normal file
@@ -0,0 +1,356 @@
|
|||||||
|
---
|
||||||
|
name: powershell-expert
|
||||||
|
description: Complete PowerShell expertise agent for cross-platform scripting, automation, CI/CD, and cloud management. PROACTIVELY activate for ANY PowerShell task including script creation, module management, Azure/AWS automation, GitHub Actions/Azure DevOps integration, PSGallery operations, debugging, and optimization. Provides expert guidance on PowerShell 7+ features, popular modules (Az, Microsoft.Graph, PnP, AWS Tools), platform-specific considerations, best practices, and production-ready patterns. Always researches latest PowerShell and module documentation when needed.
|
||||||
|
color: blue
|
||||||
|
capabilities:
|
||||||
|
- PowerShell 7+ cross-platform scripting
|
||||||
|
- Module discovery and management (PSGallery)
|
||||||
|
- CI/CD integration (GitHub Actions, Azure DevOps, Bitbucket)
|
||||||
|
- Azure automation with Az module
|
||||||
|
- AWS automation with AWS Tools
|
||||||
|
- Microsoft 365 with Microsoft.Graph
|
||||||
|
- Script optimization and debugging
|
||||||
|
- Security and best practices
|
||||||
|
---
|
||||||
|
|
||||||
|
# PowerShell Expert Agent
|
||||||
|
|
||||||
|
## 🚨 CRITICAL GUIDELINES
|
||||||
|
|
||||||
|
### Windows File Path Requirements
|
||||||
|
|
||||||
|
**MANDATORY: Always Use Backslashes on Windows for File Paths**
|
||||||
|
|
||||||
|
When using Edit or Write tools on Windows, you MUST use backslashes (`\`) in file paths, NOT forward slashes (`/`).
|
||||||
|
|
||||||
|
**Examples:**
|
||||||
|
- ❌ WRONG: `D:/repos/project/file.tsx`
|
||||||
|
- ✅ CORRECT: `D:\repos\project\file.tsx`
|
||||||
|
|
||||||
|
This applies to:
|
||||||
|
- Edit tool file_path parameter
|
||||||
|
- Write tool file_path parameter
|
||||||
|
- All file operations on Windows systems
|
||||||
|
|
||||||
|
### Documentation Guidelines
|
||||||
|
|
||||||
|
**NEVER create new documentation files unless explicitly requested by the user.**
|
||||||
|
|
||||||
|
- **Priority**: Update existing README.md files rather than creating new documentation
|
||||||
|
- **Repository cleanliness**: Keep repository root clean - only README.md unless user requests otherwise
|
||||||
|
- **Style**: Documentation should be concise, direct, and professional - avoid AI-generated tone
|
||||||
|
- **User preference**: Only create additional .md files when user specifically asks for documentation
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
Complete PowerShell expertise for all platforms, scenarios, and automation needs.
|
||||||
|
|
||||||
|
## Expertise
|
||||||
|
|
||||||
|
- **Cross-Platform PowerShell:** Windows, Linux, macOS compatibility
|
||||||
|
- **PowerShell 7+ Features:** Latest language features and performance improvements
|
||||||
|
- **Module Management:** PSGallery, module installation, updates, dependencies
|
||||||
|
- **Cloud Automation:** Azure (Az), AWS, Microsoft 365 (Graph), GCP
|
||||||
|
- **CI/CD Integration:** GitHub Actions, Azure DevOps Pipelines, Bitbucket
|
||||||
|
- **Popular Modules:** Az, Microsoft.Graph, PnP.PowerShell, AWS.Tools, Pester
|
||||||
|
- **Script Development:** Functions, error handling, parameter validation
|
||||||
|
- **Performance:** Optimization, parallel execution, efficient filtering
|
||||||
|
- **Security:** Credential management, code signing, secure practices
|
||||||
|
- **Testing:** Pester framework, PSScriptAnalyzer, code quality
|
||||||
|
|
||||||
|
## When to Activate
|
||||||
|
|
||||||
|
This agent PROACTIVELY activates for:
|
||||||
|
|
||||||
|
1. **ANY PowerShell Script Task**
|
||||||
|
- Creating new scripts
|
||||||
|
- Reviewing existing code
|
||||||
|
- Debugging script issues
|
||||||
|
- Converting between platforms
|
||||||
|
- Optimizing performance
|
||||||
|
|
||||||
|
2. **Module Operations**
|
||||||
|
- Finding modules on PSGallery
|
||||||
|
- Installing/updating modules
|
||||||
|
- Resolving module conflicts
|
||||||
|
- Managing dependencies
|
||||||
|
- Creating custom modules
|
||||||
|
|
||||||
|
3. **CI/CD Automation**
|
||||||
|
- Setting up GitHub Actions workflows
|
||||||
|
- Configuring Azure DevOps pipelines
|
||||||
|
- Bitbucket Pipelines integration
|
||||||
|
- Cross-platform testing
|
||||||
|
- Deployment automation
|
||||||
|
|
||||||
|
4. **Cloud Management**
|
||||||
|
- Azure resource automation (Az module)
|
||||||
|
- AWS resource management (AWS.Tools)
|
||||||
|
- Microsoft 365 administration (Microsoft.Graph)
|
||||||
|
- Infrastructure as Code
|
||||||
|
- Cost management scripts
|
||||||
|
|
||||||
|
5. **Development Best Practices**
|
||||||
|
- Code structure and organization
|
||||||
|
- Error handling strategies
|
||||||
|
- Parameter validation
|
||||||
|
- Comment-based help
|
||||||
|
- Security considerations
|
||||||
|
|
||||||
|
## Approach
|
||||||
|
|
||||||
|
### 1. Understand Context
|
||||||
|
|
||||||
|
First, determine:
|
||||||
|
- **Platform:** Windows/Linux/macOS or cross-platform?
|
||||||
|
- **PowerShell Version:** 7+, or 5.1 required?
|
||||||
|
- **Environment:** Local, CI/CD, cloud automation?
|
||||||
|
- **Modules:** What modules are needed/available?
|
||||||
|
|
||||||
|
### 2. Research Latest Information
|
||||||
|
|
||||||
|
For any PowerShell task:
|
||||||
|
- Check latest PowerShell 7.x documentation
|
||||||
|
- Verify module availability on PSGallery
|
||||||
|
- Look up cmdlet syntax and parameters
|
||||||
|
- Find platform-specific considerations
|
||||||
|
- Review best practices and security
|
||||||
|
|
||||||
|
### 3. Provide Expert Solution
|
||||||
|
|
||||||
|
Deliver:
|
||||||
|
- Cross-platform compatible code
|
||||||
|
- Proper error handling
|
||||||
|
- Parameter validation
|
||||||
|
- Comment-based help
|
||||||
|
- Best practice compliance
|
||||||
|
- Security considerations
|
||||||
|
- Performance optimizations
|
||||||
|
|
||||||
|
### 4. Include Examples
|
||||||
|
|
||||||
|
Always provide:
|
||||||
|
- Working code examples
|
||||||
|
- Usage scenarios
|
||||||
|
- Platform-specific notes
|
||||||
|
- Common pitfalls to avoid
|
||||||
|
- Testing approaches
|
||||||
|
|
||||||
|
## Example Scenarios
|
||||||
|
|
||||||
|
### Scenario 1: Script Creation
|
||||||
|
|
||||||
|
**User Request:** "Create a script to backup files daily"
|
||||||
|
|
||||||
|
**Agent Response:**
|
||||||
|
```powershell
|
||||||
|
<#
|
||||||
|
.SYNOPSIS
|
||||||
|
Automated file backup with timestamp
|
||||||
|
|
||||||
|
.DESCRIPTION
|
||||||
|
Cross-platform backup script that copies files from source to destination
|
||||||
|
with timestamped folders. Supports Windows, Linux, and macOS.
|
||||||
|
|
||||||
|
.PARAMETER Source
|
||||||
|
Source directory to backup
|
||||||
|
|
||||||
|
.PARAMETER Destination
|
||||||
|
Destination directory for backups
|
||||||
|
|
||||||
|
.PARAMETER RetentionDays
|
||||||
|
Number of days to keep old backups (default: 30)
|
||||||
|
|
||||||
|
.EXAMPLE
|
||||||
|
.\Backup-Files.ps1 -Source "C:\Data" -Destination "D:\Backups"
|
||||||
|
|
||||||
|
.NOTES
|
||||||
|
Requires: PowerShell 7.0+
|
||||||
|
#>
|
||||||
|
|
||||||
|
[CmdletBinding()]
|
||||||
|
param(
|
||||||
|
[Parameter(Mandatory=$true)]
|
||||||
|
[ValidateScript({Test-Path $_ -PathType Container})]
|
||||||
|
[string]$Source,
|
||||||
|
|
||||||
|
[Parameter(Mandatory=$true)]
|
||||||
|
[string]$Destination,
|
||||||
|
|
||||||
|
[Parameter()]
|
||||||
|
[ValidateRange(1, 365)]
|
||||||
|
[int]$RetentionDays = 30
|
||||||
|
)
|
||||||
|
|
||||||
|
Set-StrictMode -Version Latest
|
||||||
|
$ErrorActionPreference = "Stop"
|
||||||
|
|
||||||
|
try {
|
||||||
|
# Create destination if needed
|
||||||
|
if (-not (Test-Path $Destination)) {
|
||||||
|
New-Item -Path $Destination -ItemType Directory | Out-Null
|
||||||
|
}
|
||||||
|
|
||||||
|
# Generate timestamp
|
||||||
|
$timestamp = Get-Date -Format "yyyyMMdd_HHmmss"
|
||||||
|
$backupPath = Join-Path -Path $Destination -ChildPath "Backup_$timestamp"
|
||||||
|
|
||||||
|
Write-Verbose "Starting backup: $Source -> $backupPath"
|
||||||
|
|
||||||
|
# Perform backup
|
||||||
|
Copy-Item -Path $Source -Destination $backupPath -Recurse -Force
|
||||||
|
|
||||||
|
# Cleanup old backups
|
||||||
|
$cutoffDate = (Get-Date).AddDays(-$RetentionDays)
|
||||||
|
Get-ChildItem -Path $Destination -Directory |
|
||||||
|
Where-Object {$_.Name -match '^Backup_\d{8}_\d{6}$' -and $_.CreationTime -lt $cutoffDate} |
|
||||||
|
Remove-Item -Recurse -Force
|
||||||
|
|
||||||
|
Write-Host "✓ Backup completed: $backupPath" -ForegroundColor Green
|
||||||
|
}
|
||||||
|
catch {
|
||||||
|
Write-Error "Backup failed: $_"
|
||||||
|
exit 1
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
### Scenario 2: Module Management
|
||||||
|
|
||||||
|
**User:** "How do I work with Azure VMs?"
|
||||||
|
|
||||||
|
**Agent:**
|
||||||
|
```powershell
|
||||||
|
# Step 1: Install Azure module
|
||||||
|
Install-Module -Name Az.Compute, Az.Accounts -Scope CurrentUser -Force
|
||||||
|
|
||||||
|
# Step 2: Authenticate
|
||||||
|
Connect-AzAccount
|
||||||
|
|
||||||
|
# Step 3: Common operations
|
||||||
|
# List all VMs
|
||||||
|
Get-AzVM
|
||||||
|
|
||||||
|
# Get specific VM
|
||||||
|
$vm = Get-AzVM -ResourceGroupName "MyRG" -Name "MyVM"
|
||||||
|
|
||||||
|
# Start/Stop VM
|
||||||
|
Start-AzVM -ResourceGroupName "MyRG" -Name "MyVM"
|
||||||
|
Stop-AzVM -ResourceGroupName "MyRG" -Name "MyVM" -Force
|
||||||
|
|
||||||
|
# Get VM status
|
||||||
|
Get-AzVM -ResourceGroupName "MyRG" -Name "MyVM" -Status
|
||||||
|
```
|
||||||
|
|
||||||
|
### Scenario 3: CI/CD Setup
|
||||||
|
|
||||||
|
**User:** "Set up PowerShell in GitHub Actions"
|
||||||
|
|
||||||
|
**Agent:**
|
||||||
|
```yaml
|
||||||
|
name: PowerShell CI
|
||||||
|
|
||||||
|
on: [push, pull_request]
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
test:
|
||||||
|
runs-on: ${{ matrix.os }}
|
||||||
|
strategy:
|
||||||
|
matrix:
|
||||||
|
os: [ubuntu-latest, windows-latest, macos-latest]
|
||||||
|
|
||||||
|
steps:
|
||||||
|
- uses: actions/checkout@v4
|
||||||
|
|
||||||
|
- name: Install modules
|
||||||
|
shell: pwsh
|
||||||
|
run: |
|
||||||
|
Install-Module -Name Pester, PSScriptAnalyzer -Force -Scope CurrentUser
|
||||||
|
|
||||||
|
- name: Run tests
|
||||||
|
shell: pwsh
|
||||||
|
run: |
|
||||||
|
Invoke-Pester -Path ./tests -OutputFormat NUnitXml
|
||||||
|
|
||||||
|
- name: Code analysis
|
||||||
|
shell: pwsh
|
||||||
|
run: |
|
||||||
|
Invoke-ScriptAnalyzer -Path . -Recurse -ReportSummary
|
||||||
|
```
|
||||||
|
|
||||||
|
## Best Practices Enforced
|
||||||
|
|
||||||
|
### Cross-Platform Compatibility
|
||||||
|
- Use `Join-Path` for paths
|
||||||
|
- Detect platform with `$IsWindows`, `$IsLinux`, `$IsMacOS`
|
||||||
|
- Avoid hardcoded backslashes
|
||||||
|
- Consider case-sensitive file systems
|
||||||
|
- Use UTF-8 encoding
|
||||||
|
|
||||||
|
### Shell Detection (Windows)
|
||||||
|
- Distinguish PowerShell from Git Bash/MSYS2
|
||||||
|
- Use `$env:PSModulePath` to detect PowerShell
|
||||||
|
- Use `$MSYSTEM` environment variable for Git Bash
|
||||||
|
- Understand path conversion differences (C:\ vs /c/)
|
||||||
|
- Choose appropriate shell for the task
|
||||||
|
|
||||||
|
### Code Quality
|
||||||
|
- Use `[CmdletBinding()]` for advanced functions
|
||||||
|
- Add parameter validation attributes
|
||||||
|
- Include comment-based help
|
||||||
|
- Use `Set-StrictMode -Version Latest`
|
||||||
|
- No aliases in scripts
|
||||||
|
- Full cmdlet names
|
||||||
|
|
||||||
|
### Error Handling
|
||||||
|
- Always use `try/catch` for critical operations
|
||||||
|
- Set `$ErrorActionPreference` appropriately
|
||||||
|
- Provide meaningful error messages
|
||||||
|
- Clean up in `finally` blocks
|
||||||
|
|
||||||
|
### Security
|
||||||
|
- Never hardcode credentials
|
||||||
|
- Use `Get-Credential` or secure strings
|
||||||
|
- Leverage Azure Key Vault for secrets
|
||||||
|
- Validate all user input
|
||||||
|
- Use code signing for production
|
||||||
|
|
||||||
|
### Performance
|
||||||
|
- Use `-Filter` instead of `Where-Object` when possible
|
||||||
|
- Use `ForEach-Object -Parallel` in PowerShell 7+
|
||||||
|
- Avoid array concatenation in loops
|
||||||
|
- Use .NET methods for better performance
|
||||||
|
- Cache expensive operations
|
||||||
|
|
||||||
|
## Communication Style
|
||||||
|
|
||||||
|
The PowerShell Expert:
|
||||||
|
- **Concise:** Provides direct, actionable solutions
|
||||||
|
- **Educational:** Explains why, not just how
|
||||||
|
- **Practical:** Includes working examples
|
||||||
|
- **Proactive:** Suggests improvements and alternatives
|
||||||
|
- **Current:** Always checks latest documentation
|
||||||
|
- **Secure:** Highlights security considerations
|
||||||
|
|
||||||
|
## Tools & Resources Used
|
||||||
|
|
||||||
|
- **PSGallery:** Module discovery and installation
|
||||||
|
- **Official Docs:** Microsoft Learn PowerShell documentation
|
||||||
|
- **Module Docs:** Az, Microsoft.Graph, AWS.Tools documentation
|
||||||
|
- **Best Practices:** PowerShell Practice and Style guide
|
||||||
|
- **Testing:** Pester framework
|
||||||
|
- **Analysis:** PSScriptAnalyzer
|
||||||
|
|
||||||
|
## Success Criteria
|
||||||
|
|
||||||
|
Solutions provided by this agent will:
|
||||||
|
- ✅ Work across target platforms
|
||||||
|
- ✅ Follow PowerShell best practices
|
||||||
|
- ✅ Include proper error handling
|
||||||
|
- ✅ Be secure and production-ready
|
||||||
|
- ✅ Include examples and documentation
|
||||||
|
- ✅ Optimize for performance when needed
|
||||||
|
- ✅ Pass PSScriptAnalyzer checks
|
||||||
|
|
||||||
|
Invoke this agent for ANY PowerShell-related task to get expert, production-ready solutions with the latest best practices.
|
||||||
65
plugin.lock.json
Normal file
65
plugin.lock.json
Normal file
@@ -0,0 +1,65 @@
|
|||||||
|
{
|
||||||
|
"$schema": "internal://schemas/plugin.lock.v1.json",
|
||||||
|
"pluginId": "gh:JosiahSiegel/claude-code-marketplace:plugins/powershell-master",
|
||||||
|
"normalized": {
|
||||||
|
"repo": null,
|
||||||
|
"ref": "refs/tags/v20251128.0",
|
||||||
|
"commit": "3aa994779e3b9cca1dc6585b9e43c81850c82895",
|
||||||
|
"treeHash": "73c57dcd1237bf6159070dc2b1a6a6068f2bc8948717030c7d86c46591cb1e85",
|
||||||
|
"generatedAt": "2025-11-28T10:11:50.674455Z",
|
||||||
|
"toolVersion": "publish_plugins.py@0.2.0"
|
||||||
|
},
|
||||||
|
"origin": {
|
||||||
|
"remote": "git@github.com:zhongweili/42plugin-data.git",
|
||||||
|
"branch": "master",
|
||||||
|
"commit": "aa1497ed0949fd50e99e70d6324a29c5b34f9390",
|
||||||
|
"repoRoot": "/Users/zhongweili/projects/openmind/42plugin-data"
|
||||||
|
},
|
||||||
|
"manifest": {
|
||||||
|
"name": "powershell-master",
|
||||||
|
"description": "Complete PowerShell 7.5/7.6 expertise system across ALL platforms (Windows/Linux/macOS) with 2025 breaking changes coverage and shell detection. PROACTIVELY activate for: (1) ANY PowerShell task (scripts/modules/cmdlets), (2) PowerShell 7.5/7.6 new features (ConvertTo-CliXml, Test-Path time filtering, PSResourceGet), (3) 2025 migrations (MSOnline/AzureAD retirement, PowerShell 2.0 removal, WMIC replacement), (4) Modern security (JEA, WDAC, Constrained Language Mode), (5) CI/CD automation (GitHub Actions/Azure DevOps/Bitbucket), (6) PSResourceGet package management (2x faster than PowerShellGet), (7) Azure Az 14.5.0 with zone redundancy, (8) Microsoft.Graph 2.32.0 automation, (9) Cross-platform scripting with .NET 9 performance, (10) Shell detection and cross-shell compatibility (PowerShell vs Git Bash/MSYS2). Provides: PowerShell 7.5.4 stable / 7.6 preview features, 2025 breaking changes guidance, MSOnline/AzureAD to Microsoft.Graph migration paths, PSResourceGet adoption patterns, latest security best practices (JEA, WDAC), popular module expertise (Az 14.5.0, Microsoft.Graph 2.32.0, PnP, AWS Tools), shell detection on Windows (PowerShell vs Git Bash), path conversion knowledge, and production-ready 2025 automation patterns.",
|
||||||
|
"version": "1.5.0"
|
||||||
|
},
|
||||||
|
"content": {
|
||||||
|
"files": [
|
||||||
|
{
|
||||||
|
"path": "README.md",
|
||||||
|
"sha256": "c88be080bd5b2849f206eefc973e4c8cb6a471c38b56c89d816b824341e6ad3f"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"path": "agents/powershell-expert.md",
|
||||||
|
"sha256": "6677fea4475ffda1f07197c1dc1cf023f3d98c8908c35914faa26af487179241"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"path": ".claude-plugin/plugin.json",
|
||||||
|
"sha256": "5fc43eda4a847f84c073984571fd16b2b52d217ee4cd497f63d8aa042c259d06"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"path": "skills/powershell-2025-changes.md",
|
||||||
|
"sha256": "09b4d94918019dd070833cc34ac7e2ed34bd71b2dd01c88a96e3f91e0f8cbfca"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"path": "skills/powershell-shell-detection.md",
|
||||||
|
"sha256": "a1fc0ecb2dfe0bdb5f8e4f46dde99c1bd03abdb9a5eeb29ac0998a6bc4a3143c"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"path": "skills/powershell-7.5-features.md",
|
||||||
|
"sha256": "37d888eec7ca988213c98800e294a6d6c1b531898b191e7e83ee583cf328ac2c"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"path": "skills/powershell-security.md",
|
||||||
|
"sha256": "32b83faf81866a2ad3f5913acd34262698e171f5354597a43ac24bf2eaf6cd0c"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"path": "skills/powershell-master/SKILL.md",
|
||||||
|
"sha256": "99230d9f4385f7fed78437b11edc5d0261eb2ae406042d04011bbef6c863dcb5"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"dirSha256": "73c57dcd1237bf6159070dc2b1a6a6068f2bc8948717030c7d86c46591cb1e85"
|
||||||
|
},
|
||||||
|
"security": {
|
||||||
|
"scannedAt": null,
|
||||||
|
"scannerVersion": null,
|
||||||
|
"flags": []
|
||||||
|
}
|
||||||
|
}
|
||||||
337
skills/powershell-2025-changes.md
Normal file
337
skills/powershell-2025-changes.md
Normal file
@@ -0,0 +1,337 @@
|
|||||||
|
---
|
||||||
|
name: powershell-2025-changes
|
||||||
|
description: Critical PowerShell changes, deprecations, and migrations for 2025
|
||||||
|
---
|
||||||
|
|
||||||
|
# PowerShell 2025 Breaking Changes & Migrations
|
||||||
|
|
||||||
|
Critical changes, deprecations, and migration paths for PowerShell in 2025.
|
||||||
|
|
||||||
|
## PowerShell 2.0 Removal (August-September 2025)
|
||||||
|
|
||||||
|
### What's Removed
|
||||||
|
|
||||||
|
PowerShell 2.0 has been **completely removed** from:
|
||||||
|
- **Windows 11 version 24H2** (August 2025)
|
||||||
|
- **Windows Server 2025** (September 2025)
|
||||||
|
|
||||||
|
**Why:** Security improvements, reduced attack surface, legacy code cleanup
|
||||||
|
|
||||||
|
### Migration Path
|
||||||
|
|
||||||
|
```powershell
|
||||||
|
# Check if PowerShell 2.0 is installed
|
||||||
|
Get-WindowsOptionalFeature -Online -FeatureName MicrosoftWindowsPowerShellV2Root
|
||||||
|
|
||||||
|
# If you still need PowerShell 2.0 (NOT RECOMMENDED)
|
||||||
|
# - Use older Windows versions
|
||||||
|
# - Use Windows containers with older base images
|
||||||
|
# - Upgrade scripts to PowerShell 5.1 or 7+
|
||||||
|
|
||||||
|
# Recommended: Migrate to PowerShell 7.5+
|
||||||
|
winget install Microsoft.PowerShell
|
||||||
|
```
|
||||||
|
|
||||||
|
**Action Required:** Audit all scripts and remove `-Version 2.0` parameters from any PowerShell invocations.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## MSOnline & AzureAD Module Retirement
|
||||||
|
|
||||||
|
### Retirement Timeline
|
||||||
|
|
||||||
|
| Module | Stop Working | Retirement Complete |
|
||||||
|
|--------|--------------|---------------------|
|
||||||
|
| **MSOnline** | Late May 2025 | May 31, 2025 |
|
||||||
|
| **AzureAD** | March 30, 2025 | After July 1, 2025 |
|
||||||
|
|
||||||
|
**Critical:** These modules will stop functioning - not just deprecated, but **completely non-functional**.
|
||||||
|
|
||||||
|
### Migration Path
|
||||||
|
|
||||||
|
**From MSOnline/AzureAD to Microsoft.Graph:**
|
||||||
|
|
||||||
|
```powershell
|
||||||
|
# OLD (MSOnline) - STOPS WORKING MAY 2025
|
||||||
|
Connect-MsolService
|
||||||
|
Get-MsolUser
|
||||||
|
Set-MsolUser -UserPrincipalName "user@domain.com" -UsageLocation "US"
|
||||||
|
|
||||||
|
# NEW (Microsoft.Graph 2.32.0)
|
||||||
|
Connect-MgGraph -Scopes "User.ReadWrite.All"
|
||||||
|
Get-MgUser
|
||||||
|
Update-MgUser -UserId "user@domain.com" -UsageLocation "US"
|
||||||
|
|
||||||
|
# OLD (AzureAD) - STOPS WORKING MARCH 2025
|
||||||
|
Connect-AzureAD
|
||||||
|
Get-AzureADUser
|
||||||
|
New-AzureADUser -DisplayName "John Doe" -UserPrincipalName "john@domain.com"
|
||||||
|
|
||||||
|
# NEW (Microsoft.Graph 2.32.0)
|
||||||
|
Connect-MgGraph -Scopes "User.ReadWrite.All"
|
||||||
|
Get-MgUser
|
||||||
|
New-MgUser -DisplayName "John Doe" -UserPrincipalName "john@domain.com"
|
||||||
|
```
|
||||||
|
|
||||||
|
**Alternative:** Use Microsoft Entra PowerShell module (successor to AzureAD)
|
||||||
|
|
||||||
|
```powershell
|
||||||
|
Install-Module -Name Microsoft.Graph.Entra -Scope CurrentUser
|
||||||
|
Connect-Entra
|
||||||
|
Get-EntraUser
|
||||||
|
```
|
||||||
|
|
||||||
|
### Common Command Mappings
|
||||||
|
|
||||||
|
| MSOnline/AzureAD | Microsoft.Graph | Notes |
|
||||||
|
|------------------|----------------|-------|
|
||||||
|
| `Get-MsolUser` / `Get-AzureADUser` | `Get-MgUser` | Requires User.Read.All scope |
|
||||||
|
| `Get-MsolGroup` / `Get-AzureADGroup` | `Get-MgGroup` | Requires Group.Read.All scope |
|
||||||
|
| `Get-MsolDevice` / `Get-AzureADDevice` | `Get-MgDevice` | Requires Device.Read.All scope |
|
||||||
|
| `Connect-MsolService` / `Connect-AzureAD` | `Connect-MgGraph` | Scope-based permissions |
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## WMIC Removal (Windows 11 25H2)
|
||||||
|
|
||||||
|
### What's Removed
|
||||||
|
|
||||||
|
**Windows Management Instrumentation Command-line (WMIC)** tool removed after upgrading to Windows 11 25H2+.
|
||||||
|
|
||||||
|
### Migration Path
|
||||||
|
|
||||||
|
**From WMIC to PowerShell WMI/CIM:**
|
||||||
|
|
||||||
|
```powershell
|
||||||
|
# OLD (WMIC) - REMOVED
|
||||||
|
wmic process list brief
|
||||||
|
wmic os get caption
|
||||||
|
|
||||||
|
# NEW (PowerShell CIM)
|
||||||
|
Get-CimInstance -ClassName Win32_Process | Select-Object Name, ProcessId, CommandLine
|
||||||
|
Get-CimInstance -ClassName Win32_OperatingSystem | Select-Object Caption, Version
|
||||||
|
|
||||||
|
# For detailed process info
|
||||||
|
Get-Process | Format-Table Name, Id, CPU, WorkingSet -AutoSize
|
||||||
|
|
||||||
|
# For system info
|
||||||
|
Get-ComputerInfo | Select-Object WindowsProductName, WindowsVersion
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## PowerShellGet → PSResourceGet Migration
|
||||||
|
|
||||||
|
### Modern Package Management (2025)
|
||||||
|
|
||||||
|
**PSResourceGet** is the official successor to PowerShellGet (2x faster, actively developed).
|
||||||
|
|
||||||
|
```powershell
|
||||||
|
# Install PSResourceGet (ships with PowerShell 7.4+)
|
||||||
|
Install-Module -Name Microsoft.PowerShell.PSResourceGet -Force
|
||||||
|
|
||||||
|
# New commands (PSResourceGet)
|
||||||
|
Install-PSResource -Name Az -Scope CurrentUser # Replaces Install-Module
|
||||||
|
Find-PSResource -Name "*Azure*" # Replaces Find-Module
|
||||||
|
Update-PSResource -Name Az # Replaces Update-Module
|
||||||
|
Get-InstalledPSResource # Replaces Get-InstalledModule
|
||||||
|
|
||||||
|
# Compatibility layer available for legacy scripts
|
||||||
|
# Your old Install-Module commands still work but call PSResourceGet internally
|
||||||
|
```
|
||||||
|
|
||||||
|
**Performance Comparison:**
|
||||||
|
- **PowerShellGet**: 10-15 seconds to install module
|
||||||
|
- **PSResourceGet**: 5-7 seconds to install module (2x faster)
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Test-Json Schema Changes
|
||||||
|
|
||||||
|
### Breaking Change (PowerShell 7.4+)
|
||||||
|
|
||||||
|
**Test-Json** now uses **JsonSchema.NET** instead of **Newtonsoft.Json.Schema**.
|
||||||
|
|
||||||
|
**Impact:** No longer supports Draft 4 JSON schemas.
|
||||||
|
|
||||||
|
```powershell
|
||||||
|
# OLD (Draft 4 schema) - NO LONGER SUPPORTED
|
||||||
|
$schema = @"
|
||||||
|
{
|
||||||
|
"$schema": "http://json-schema.org/draft-04/schema#",
|
||||||
|
"type": "object"
|
||||||
|
}
|
||||||
|
"@
|
||||||
|
|
||||||
|
Test-Json -Json $json -Schema $schema # FAILS in PowerShell 7.4+
|
||||||
|
|
||||||
|
# NEW (Draft 6+ schema) - SUPPORTED
|
||||||
|
$schema = @"
|
||||||
|
{
|
||||||
|
"$schema": "http://json-schema.org/draft-06/schema#",
|
||||||
|
"type": "object"
|
||||||
|
}
|
||||||
|
"@
|
||||||
|
|
||||||
|
Test-Json -Json $json -Schema $schema # WORKS
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## #Requires -PSSnapin Removed
|
||||||
|
|
||||||
|
### Breaking Change (PowerShell 7.4+)
|
||||||
|
|
||||||
|
All code related to `#Requires -PSSnapin` has been removed.
|
||||||
|
|
||||||
|
```powershell
|
||||||
|
# OLD (PowerShell 5.1 and earlier)
|
||||||
|
#Requires -PSSnapin Microsoft.Exchange.Management.PowerShell.SnapIn
|
||||||
|
|
||||||
|
# NEW (Use modules instead)
|
||||||
|
#Requires -Modules ExchangeOnlineManagement
|
||||||
|
|
||||||
|
Import-Module ExchangeOnlineManagement
|
||||||
|
Connect-ExchangeOnline
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Security Hardening (2025 Standards)
|
||||||
|
|
||||||
|
### Just Enough Administration (JEA)
|
||||||
|
|
||||||
|
**JEA** is now a security requirement for production environments:
|
||||||
|
|
||||||
|
```powershell
|
||||||
|
# Create JEA session configuration
|
||||||
|
New-PSSessionConfigurationFile -SessionType RestrictedRemoteServer `
|
||||||
|
-Path "C:\JEA\RestrictedAdmin.pssc" `
|
||||||
|
-VisibleCmdlets @{
|
||||||
|
Name = 'Restart-Service'
|
||||||
|
Parameters = @{ Name = 'Name'; ValidateSet = 'Spooler' }
|
||||||
|
} `
|
||||||
|
-LanguageMode NoLanguage
|
||||||
|
|
||||||
|
# Register JEA endpoint
|
||||||
|
Register-PSSessionConfiguration -Name RestrictedAdmin `
|
||||||
|
-Path "C:\JEA\RestrictedAdmin.pssc" `
|
||||||
|
-Force
|
||||||
|
|
||||||
|
# Connect with limited privileges
|
||||||
|
Enter-PSSession -ComputerName Server01 -ConfigurationName RestrictedAdmin
|
||||||
|
```
|
||||||
|
|
||||||
|
### Windows Defender Application Control (WDAC)
|
||||||
|
|
||||||
|
**WDAC** replaces AppLocker for PowerShell script control:
|
||||||
|
|
||||||
|
```powershell
|
||||||
|
# Create WDAC policy for PowerShell scripts
|
||||||
|
New-CIPolicy -FilePath "C:\WDAC\PowerShellPolicy.xml" `
|
||||||
|
-ScanPath "C:\Scripts" `
|
||||||
|
-Level FilePublisher `
|
||||||
|
-Fallback Hash
|
||||||
|
|
||||||
|
# Convert to binary and deploy
|
||||||
|
ConvertFrom-CIPolicy -XmlFilePath "C:\WDAC\PowerShellPolicy.xml" `
|
||||||
|
-BinaryFilePath "C:\Windows\System32\CodeIntegrity\SIPolicy.p7b"
|
||||||
|
```
|
||||||
|
|
||||||
|
### Constrained Language Mode
|
||||||
|
|
||||||
|
**Constrained Language Mode** is now recommended for all users without admin privileges:
|
||||||
|
|
||||||
|
```powershell
|
||||||
|
# Check current language mode
|
||||||
|
$ExecutionContext.SessionState.LanguageMode
|
||||||
|
# Output: FullLanguage (admin) or ConstrainedLanguage (standard user)
|
||||||
|
|
||||||
|
# Set system-wide constrained language mode via Group Policy or Environment Variable
|
||||||
|
# Set HKLM:\SYSTEM\CurrentControlSet\Control\Session Manager\Environment\__PSLockdownPolicy = 4
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## PowerShell 7.6 Preview Features
|
||||||
|
|
||||||
|
### Current Status (October 2025)
|
||||||
|
|
||||||
|
PowerShell 7.6.0 Preview 5 available (built on .NET 9.0.101)
|
||||||
|
|
||||||
|
**New Features:**
|
||||||
|
- **PSRedirectToVariable**: Allow redirecting to a variable
|
||||||
|
- **Module Rename**: ThreadJob → Microsoft.PowerShell.ThreadJob
|
||||||
|
- **PSResourceGet 1.1.0**: Improved performance and Azure Artifacts support
|
||||||
|
|
||||||
|
```powershell
|
||||||
|
# Check PowerShell version
|
||||||
|
$PSVersionTable.PSVersion
|
||||||
|
# 7.5.4 (stable) or 7.6.0-preview.5
|
||||||
|
|
||||||
|
# .NET version
|
||||||
|
[System.Runtime.InteropServices.RuntimeInformation]::FrameworkDescription
|
||||||
|
# .NET 9.0.101
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Migration Checklist
|
||||||
|
|
||||||
|
### Immediate Actions Required (2025)
|
||||||
|
|
||||||
|
- [ ] **Audit MSOnline/AzureAD usage** - Migrate to Microsoft.Graph 2.32.0 before May 2025
|
||||||
|
- [ ] **Remove PowerShell 2.0 references** - Upgrade to PowerShell 7.5+
|
||||||
|
- [ ] **Replace WMIC commands** - Use Get-CimInstance/Get-Process
|
||||||
|
- [ ] **Update JSON schemas** - Migrate Draft 4 to Draft 6+
|
||||||
|
- [ ] **Remove PSSnapin requirements** - Convert to modules
|
||||||
|
- [ ] **Adopt PSResourceGet** - Faster, modern package management
|
||||||
|
- [ ] **Implement JEA** - Role-based access control for production
|
||||||
|
- [ ] **Enable WDAC** - Application control for PowerShell scripts
|
||||||
|
- [ ] **Test Constrained Language Mode** - For non-admin users
|
||||||
|
|
||||||
|
### Recommended Actions
|
||||||
|
|
||||||
|
- [ ] **Upgrade to PowerShell 7.5.4** - Latest stable with .NET 9
|
||||||
|
- [ ] **Adopt Az 14.5.0** - Latest Azure module with zone redundancy
|
||||||
|
- [ ] **Use Microsoft.Graph 2.32.0** - Actively maintained Graph SDK
|
||||||
|
- [ ] **Enable Script Block Logging** - Security auditing
|
||||||
|
- [ ] **Implement Code Signing** - For production scripts
|
||||||
|
- [ ] **Use Azure Key Vault** - For credential management
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Testing Migration
|
||||||
|
|
||||||
|
```powershell
|
||||||
|
# Test for deprecated module usage
|
||||||
|
Get-Module MSOnline, AzureAD -ListAvailable
|
||||||
|
# If found, plan migration immediately
|
||||||
|
|
||||||
|
# Test for PowerShell 2.0 dependencies
|
||||||
|
Get-Content "script.ps1" | Select-String -Pattern "powershell.exe -Version 2"
|
||||||
|
# If found, remove version parameter
|
||||||
|
|
||||||
|
# Test for WMIC usage
|
||||||
|
Get-ChildItem -Path "C:\Scripts" -Recurse -Filter "*.ps1" |
|
||||||
|
Select-String -Pattern "wmic" |
|
||||||
|
Select-Object Path, Line
|
||||||
|
|
||||||
|
# Verify PowerShell version compatibility
|
||||||
|
#Requires -Version 7.0
|
||||||
|
Test-Path $PSCommandPath # Ensures script is PowerShell 7+
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Resources
|
||||||
|
|
||||||
|
- [PowerShell 7.5 Release Notes](https://learn.microsoft.com/en-us/powershell/scripting/whats-new/what-s-new-in-powershell-75)
|
||||||
|
- [MSOnline/AzureAD Retirement Info](https://techcommunity.microsoft.com/blog/microsoft-entra-blog/action-required-msonline-and-azuread-powershell-retirement---2025-info-and-resou/4364991)
|
||||||
|
- [PSResourceGet Documentation](https://learn.microsoft.com/en-us/powershell/module/microsoft.powershell.psresourceget)
|
||||||
|
- [JEA Documentation](https://learn.microsoft.com/en-us/powershell/scripting/security/remoting/jea/overview)
|
||||||
|
- [WDAC Documentation](https://learn.microsoft.com/en-us/windows/security/application-security/application-control/windows-defender-application-control)
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
**Last Updated:** October 2025
|
||||||
420
skills/powershell-7.5-features.md
Normal file
420
skills/powershell-7.5-features.md
Normal file
@@ -0,0 +1,420 @@
|
|||||||
|
---
|
||||||
|
name: powershell-7.5-features
|
||||||
|
description: PowerShell 7.5 new features and cmdlets built on .NET 9
|
||||||
|
---
|
||||||
|
|
||||||
|
# PowerShell 7.5 New Features
|
||||||
|
|
||||||
|
PowerShell 7.5 GA (General Availability: January 2025) - Latest stable version 7.5.4 (October 2025) built on .NET 9.0.306 with significant performance and memory enhancements.
|
||||||
|
|
||||||
|
## New Cmdlets
|
||||||
|
|
||||||
|
### ConvertTo-CliXml and ConvertFrom-CliXml
|
||||||
|
|
||||||
|
Convert objects to/from CLI XML format without file I/O:
|
||||||
|
|
||||||
|
```powershell
|
||||||
|
# ConvertTo-CliXml - Convert object to XML string
|
||||||
|
$process = Get-Process -Name pwsh
|
||||||
|
$xmlString = $process | ConvertTo-CliXml
|
||||||
|
|
||||||
|
# ConvertFrom-CliXml - Convert XML string back to object
|
||||||
|
$restored = $xmlString | ConvertFrom-CliXml
|
||||||
|
$restored.ProcessName # Outputs: pwsh
|
||||||
|
|
||||||
|
# Use cases:
|
||||||
|
# - Serialize objects for API transmission
|
||||||
|
# - Store object state in databases/caches
|
||||||
|
# - Share objects across PowerShell sessions
|
||||||
|
# - Clipboard operations with rich objects
|
||||||
|
```
|
||||||
|
|
||||||
|
**Difference from Export/Import-Clixml:**
|
||||||
|
- `Export-Clixml`: Writes to file
|
||||||
|
- `ConvertTo-CliXml`: Returns string (no file I/O)
|
||||||
|
|
||||||
|
## Enhanced Test-Path Cmdlet
|
||||||
|
|
||||||
|
### -OlderThan and -NewerThan Parameters
|
||||||
|
|
||||||
|
Filter paths by modification time:
|
||||||
|
|
||||||
|
```powershell
|
||||||
|
# Find files older than 30 days
|
||||||
|
Test-Path "C:\Logs\*.log" -OlderThan (Get-Date).AddDays(-30)
|
||||||
|
|
||||||
|
# Find files newer than 1 hour
|
||||||
|
Test-Path "C:\Temp\*" -NewerThan (Get-Date).AddHours(-1)
|
||||||
|
|
||||||
|
# Cleanup old log files
|
||||||
|
Get-ChildItem "C:\Logs" -Filter "*.log" |
|
||||||
|
Where-Object { Test-Path $_.FullName -OlderThan (Get-Date).AddDays(-90) } |
|
||||||
|
Remove-Item -WhatIf
|
||||||
|
|
||||||
|
# Find recent downloads
|
||||||
|
Get-ChildItem "C:\Users\*\Downloads" -Recurse |
|
||||||
|
Where-Object { Test-Path $_.FullName -NewerThan (Get-Date).AddDays(-7) }
|
||||||
|
```
|
||||||
|
|
||||||
|
**Use Cases:**
|
||||||
|
- Log rotation automation
|
||||||
|
- Backup file cleanup
|
||||||
|
- Recent file monitoring
|
||||||
|
- Cache invalidation
|
||||||
|
|
||||||
|
## Enhanced Web Cmdlets
|
||||||
|
|
||||||
|
### -PassThru with -OutFile
|
||||||
|
|
||||||
|
Save response to file AND return content:
|
||||||
|
|
||||||
|
```powershell
|
||||||
|
# Before PowerShell 7.5 (choose one):
|
||||||
|
Invoke-WebRequest -Uri $url -OutFile "download.zip" # Save only
|
||||||
|
$response = Invoke-WebRequest -Uri $url # Return only
|
||||||
|
|
||||||
|
# PowerShell 7.5 (both):
|
||||||
|
$response = Invoke-WebRequest -Uri $url -OutFile "download.zip" -PassThru
|
||||||
|
$response.StatusCode # 200
|
||||||
|
# File also saved to download.zip
|
||||||
|
|
||||||
|
# Download and verify
|
||||||
|
$result = Invoke-RestMethod -Uri "https://api.example.com/data.json" `
|
||||||
|
-OutFile "data.json" `
|
||||||
|
-PassThru
|
||||||
|
|
||||||
|
Write-Host "Downloaded $($result.Length) bytes"
|
||||||
|
# File saved to data.json
|
||||||
|
```
|
||||||
|
|
||||||
|
**Benefits:**
|
||||||
|
- Download progress tracking
|
||||||
|
- HTTP header inspection
|
||||||
|
- Status code verification
|
||||||
|
- Combined file save + content processing
|
||||||
|
|
||||||
|
## Enhanced Test-Json Cmdlet
|
||||||
|
|
||||||
|
### IgnoreComments and AllowTrailingCommas
|
||||||
|
|
||||||
|
Parse relaxed JSON formats:
|
||||||
|
|
||||||
|
```powershell
|
||||||
|
# JSON with comments (previously invalid)
|
||||||
|
$jsonWithComments = @"
|
||||||
|
{
|
||||||
|
// This is a comment
|
||||||
|
"name": "example", // inline comment
|
||||||
|
/* Multi-line
|
||||||
|
comment */
|
||||||
|
"version": "1.0"
|
||||||
|
}
|
||||||
|
"@
|
||||||
|
|
||||||
|
# PowerShell 7.5 - Parse with comments
|
||||||
|
$obj = $jsonWithComments | ConvertFrom-Json -IgnoreComments
|
||||||
|
$obj.name # Outputs: example
|
||||||
|
|
||||||
|
# JSON with trailing commas (previously invalid)
|
||||||
|
$jsonTrailing = @"
|
||||||
|
{
|
||||||
|
"items": [
|
||||||
|
"first",
|
||||||
|
"second", // trailing comma
|
||||||
|
],
|
||||||
|
}
|
||||||
|
"@
|
||||||
|
|
||||||
|
# PowerShell 7.5 - Parse with trailing commas
|
||||||
|
$obj = $jsonTrailing | ConvertFrom-Json -AllowTrailingCommas
|
||||||
|
|
||||||
|
# Validate JSON with relaxed syntax
|
||||||
|
Test-Json -Json $jsonWithComments -IgnoreComments
|
||||||
|
Test-Json -Json $jsonTrailing -AllowTrailingCommas
|
||||||
|
```
|
||||||
|
|
||||||
|
**Use Cases:**
|
||||||
|
- Parse configuration files with comments
|
||||||
|
- Handle JSON from JavaScript tools
|
||||||
|
- Accept relaxed JSON from APIs
|
||||||
|
- Config file validation
|
||||||
|
|
||||||
|
## Enhanced Resolve-Path and Convert-Path
|
||||||
|
|
||||||
|
### -Force Parameter for Wildcard Hidden Files
|
||||||
|
|
||||||
|
Access hidden/system files with wildcards:
|
||||||
|
|
||||||
|
```powershell
|
||||||
|
# PowerShell 7.4 and earlier - Hidden files not matched
|
||||||
|
Resolve-Path "C:\Users\*\.*" | Select-Object -First 5
|
||||||
|
# Skips .vscode, .gitignore, etc.
|
||||||
|
|
||||||
|
# PowerShell 7.5 - Include hidden files
|
||||||
|
Resolve-Path "C:\Users\*\.*" -Force | Select-Object -First 5
|
||||||
|
# Includes .vscode, .gitignore, .bashrc, etc.
|
||||||
|
|
||||||
|
# Find all hidden config files
|
||||||
|
Resolve-Path "C:\Projects\*\.*" -Force |
|
||||||
|
Where-Object { (Get-Item $_).Attributes -match "Hidden" }
|
||||||
|
|
||||||
|
# Convert-Path also supports -Force
|
||||||
|
Convert-Path "~/.config/*" -Force
|
||||||
|
```
|
||||||
|
|
||||||
|
**Use Cases:**
|
||||||
|
- Backup scripts including hidden files
|
||||||
|
- Configuration discovery
|
||||||
|
- Security audits
|
||||||
|
- Development environment setup
|
||||||
|
|
||||||
|
## New-FileCatalog Version 2 Default
|
||||||
|
|
||||||
|
FileCatalog version 2 is now default:
|
||||||
|
|
||||||
|
```powershell
|
||||||
|
# PowerShell 7.5 - Version 2 by default
|
||||||
|
New-FileCatalog -Path "C:\Project" -CatalogFilePath "catalog.cat"
|
||||||
|
# Creates version 2 catalog (SHA256)
|
||||||
|
|
||||||
|
# Explicitly specify version
|
||||||
|
New-FileCatalog -Path "C:\Project" `
|
||||||
|
-CatalogFilePath "catalog.cat" `
|
||||||
|
-CatalogVersion 2
|
||||||
|
|
||||||
|
# Test file integrity
|
||||||
|
Test-FileCatalog -Path "C:\Project" -CatalogFilePath "catalog.cat"
|
||||||
|
```
|
||||||
|
|
||||||
|
**Version Differences:**
|
||||||
|
- Version 1: SHA1 hashing (legacy)
|
||||||
|
- Version 2: SHA256 hashing (default, more secure)
|
||||||
|
|
||||||
|
## .NET 9 Performance Enhancements
|
||||||
|
|
||||||
|
### Significant Performance Improvements
|
||||||
|
|
||||||
|
```powershell
|
||||||
|
# PowerShell 7.5 benefits from .NET 9.0.306:
|
||||||
|
# - Faster startup time
|
||||||
|
# - Reduced memory consumption
|
||||||
|
# - Improved JIT compilation
|
||||||
|
# - Better garbage collection
|
||||||
|
|
||||||
|
# Example: Large dataset processing
|
||||||
|
Measure-Command {
|
||||||
|
1..1000000 | ForEach-Object { $_ * 2 }
|
||||||
|
}
|
||||||
|
# PowerShell 7.4: ~2.5 seconds
|
||||||
|
# PowerShell 7.5: ~1.8 seconds (28% faster)
|
||||||
|
```
|
||||||
|
|
||||||
|
### Memory Efficiency
|
||||||
|
|
||||||
|
```powershell
|
||||||
|
# Lower memory footprint for:
|
||||||
|
# - Large collections
|
||||||
|
# - Long-running scripts
|
||||||
|
# - Concurrent operations
|
||||||
|
# - Pipeline processing
|
||||||
|
|
||||||
|
# Monitor memory usage
|
||||||
|
[System.GC]::GetTotalMemory($false) / 1MB
|
||||||
|
# PowerShell 7.5 uses 15-20% less memory on average
|
||||||
|
```
|
||||||
|
|
||||||
|
## PSResourceGet 1.1.1 (March 2025)
|
||||||
|
|
||||||
|
### Modern Package Management
|
||||||
|
|
||||||
|
PSResourceGet is the official successor to PowerShellGet, offering significant performance improvements and enhanced security.
|
||||||
|
|
||||||
|
**Key Features:**
|
||||||
|
- **2x faster** module installation
|
||||||
|
- **Improved security** - SecretManagement integration for secure credential storage
|
||||||
|
- **Azure Artifacts support** - Enterprise private feed integration
|
||||||
|
- **Better error handling** - Clearer error messages and retry logic
|
||||||
|
|
||||||
|
```powershell
|
||||||
|
# Install PSResourceGet (included in PowerShell 7.4+)
|
||||||
|
Install-Module -Name Microsoft.PowerShell.PSResourceGet -Force
|
||||||
|
|
||||||
|
# New commands
|
||||||
|
Install-PSResource -Name Az -Scope CurrentUser # 2x faster than Install-Module
|
||||||
|
Find-PSResource -Name "*Azure*" # Replaces Find-Module
|
||||||
|
Update-PSResource -Name Az # Replaces Update-Module
|
||||||
|
Get-InstalledPSResource # Replaces Get-InstalledModule
|
||||||
|
|
||||||
|
# Security best practice - use SecretManagement for credentials
|
||||||
|
Register-PSResourceRepository -Name "PrivateFeed" `
|
||||||
|
-Uri "https://pkgs.dev.azure.com/org/project/_packaging/feed/nuget/v3/index.json" `
|
||||||
|
-Trusted
|
||||||
|
|
||||||
|
# Retrieve credential from SecretManagement vault
|
||||||
|
$credential = Get-Secret -Name "AzureArtifactsToken" -AsPlainText
|
||||||
|
Install-PSResource -Name "MyPrivateModule" -Repository "PrivateFeed" -Credential $credential
|
||||||
|
```
|
||||||
|
|
||||||
|
**Performance Comparison:**
|
||||||
|
| Operation | PowerShellGet | PSResourceGet 1.1.1 | Improvement |
|
||||||
|
|-----------|--------------|---------------------|-------------|
|
||||||
|
| Install module | 10-15s | 5-7s | 2x faster |
|
||||||
|
| Search modules | 3-5s | 1-2s | 2-3x faster |
|
||||||
|
| Update module | 12-18s | 6-9s | 2x faster |
|
||||||
|
|
||||||
|
**Security Enhancements:**
|
||||||
|
- Never use plaintext credentials in scripts
|
||||||
|
- Use SecretManagement module for storing repository credentials
|
||||||
|
- Support for Azure DevOps Personal Access Tokens (PAT)
|
||||||
|
- Integrated authentication with Azure Artifacts
|
||||||
|
|
||||||
|
```powershell
|
||||||
|
# WRONG - plaintext credential
|
||||||
|
$cred = New-Object PSCredential("user", (ConvertTo-SecureString "password" -AsPlainText -Force))
|
||||||
|
|
||||||
|
# CORRECT - SecretManagement
|
||||||
|
Install-Module Microsoft.PowerShell.SecretManagement
|
||||||
|
Register-SecretVault -Name LocalVault -ModuleName Microsoft.PowerShell.SecretStore
|
||||||
|
Set-Secret -Name "RepoToken" -Secret "your-token"
|
||||||
|
|
||||||
|
$token = Get-Secret -Name "RepoToken" -AsPlainText
|
||||||
|
Install-PSResource -Name "Module" -Repository "Feed" -Credential $token
|
||||||
|
```
|
||||||
|
|
||||||
|
## Migration from PowerShell 7.4
|
||||||
|
|
||||||
|
### Check Version
|
||||||
|
|
||||||
|
```powershell
|
||||||
|
# Current version
|
||||||
|
$PSVersionTable.PSVersion
|
||||||
|
# 7.5.4 (latest stable as of October 2025)
|
||||||
|
|
||||||
|
# .NET version
|
||||||
|
[System.Runtime.InteropServices.RuntimeInformation]::FrameworkDescription
|
||||||
|
# .NET 9.0.306
|
||||||
|
|
||||||
|
# PSResourceGet version
|
||||||
|
Get-Module Microsoft.PowerShell.PSResourceGet -ListAvailable
|
||||||
|
# Version 1.1.1 (latest as of March 2025)
|
||||||
|
```
|
||||||
|
|
||||||
|
### Update Scripts for 7.5
|
||||||
|
|
||||||
|
```powershell
|
||||||
|
# Replace file-based XML serialization
|
||||||
|
# Before:
|
||||||
|
$data | Export-Clixml -Path "temp.xml"
|
||||||
|
$xml = Get-Content "temp.xml" -Raw
|
||||||
|
Remove-Item "temp.xml"
|
||||||
|
|
||||||
|
# After:
|
||||||
|
$xml = $data | ConvertTo-CliXml
|
||||||
|
|
||||||
|
# Use new Test-Path filtering
|
||||||
|
# Before:
|
||||||
|
Get-ChildItem | Where-Object {
|
||||||
|
$_.LastWriteTime -lt (Get-Date).AddDays(-30)
|
||||||
|
}
|
||||||
|
|
||||||
|
# After:
|
||||||
|
Get-ChildItem | Where-Object {
|
||||||
|
Test-Path $_.FullName -OlderThan (Get-Date).AddDays(-30)
|
||||||
|
}
|
||||||
|
|
||||||
|
# Leverage -PassThru for downloads
|
||||||
|
# Before:
|
||||||
|
Invoke-WebRequest -Uri $url -OutFile "file.zip"
|
||||||
|
$size = (Get-Item "file.zip").Length
|
||||||
|
|
||||||
|
# After:
|
||||||
|
$response = Invoke-WebRequest -Uri $url -OutFile "file.zip" -PassThru
|
||||||
|
$size = $response.RawContentLength
|
||||||
|
```
|
||||||
|
|
||||||
|
## Best Practices for PowerShell 7.5
|
||||||
|
|
||||||
|
1. **Use ConvertTo/From-CliXml for in-memory serialization:**
|
||||||
|
```powershell
|
||||||
|
# Serialize to clipboard
|
||||||
|
$data | ConvertTo-CliXml | Set-Clipboard
|
||||||
|
|
||||||
|
# Deserialize from clipboard
|
||||||
|
$restored = Get-Clipboard | ConvertFrom-CliXml
|
||||||
|
```
|
||||||
|
|
||||||
|
2. **Leverage Test-Path time filtering:**
|
||||||
|
```powershell
|
||||||
|
# Clean old logs
|
||||||
|
Get-ChildItem "C:\Logs" | Where-Object {
|
||||||
|
Test-Path $_.FullName -OlderThan (Get-Date).AddDays(-90)
|
||||||
|
} | Remove-Item
|
||||||
|
```
|
||||||
|
|
||||||
|
3. **Use -Force for hidden file operations:**
|
||||||
|
```powershell
|
||||||
|
# Backup including hidden config files
|
||||||
|
Resolve-Path "~/*" -Force |
|
||||||
|
Where-Object { Test-Path $_ -OlderThan (Get-Date).AddDays(-1) } |
|
||||||
|
Copy-Item -Destination "C:\Backup\"
|
||||||
|
```
|
||||||
|
|
||||||
|
4. **Simplify download workflows:**
|
||||||
|
```powershell
|
||||||
|
# Download and verify in one step
|
||||||
|
$response = Invoke-WebRequest $url -OutFile "data.zip" -PassThru
|
||||||
|
if ($response.StatusCode -eq 200) {
|
||||||
|
Expand-Archive "data.zip" -Destination "data/"
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
5. **Parse relaxed JSON:**
|
||||||
|
```powershell
|
||||||
|
# Configuration files with comments
|
||||||
|
$config = Get-Content "config.jsonc" -Raw |
|
||||||
|
ConvertFrom-Json -IgnoreComments
|
||||||
|
```
|
||||||
|
|
||||||
|
## CI/CD Integration
|
||||||
|
|
||||||
|
```yaml
|
||||||
|
# GitHub Actions with PowerShell 7.5
|
||||||
|
- name: Setup PowerShell 7.5
|
||||||
|
uses: actions/setup-powershell@v1
|
||||||
|
with:
|
||||||
|
pwsh-version: '7.5.x'
|
||||||
|
|
||||||
|
- name: Run Script with 7.5 Features
|
||||||
|
shell: pwsh
|
||||||
|
run: |
|
||||||
|
# Use ConvertTo-CliXml for artifact storage
|
||||||
|
$results = ./Invoke-Tests.ps1
|
||||||
|
$results | ConvertTo-CliXml | Out-File "results.xml"
|
||||||
|
|
||||||
|
# Download dependencies with -PassThru
|
||||||
|
$response = Invoke-WebRequest $depUrl -OutFile "deps.zip" -PassThru
|
||||||
|
Write-Host "Downloaded $($response.RawContentLength) bytes"
|
||||||
|
```
|
||||||
|
|
||||||
|
## Backward Compatibility
|
||||||
|
|
||||||
|
PowerShell 7.5 maintains compatibility with 7.x scripts:
|
||||||
|
- All 7.0-7.4 scripts work unchanged
|
||||||
|
- New parameters are opt-in
|
||||||
|
- No breaking changes to existing cmdlets
|
||||||
|
- Module compatibility preserved
|
||||||
|
|
||||||
|
## Performance Benchmarks
|
||||||
|
|
||||||
|
| Operation | PowerShell 7.4 | PowerShell 7.5 | Improvement |
|
||||||
|
|-----------|---------------|---------------|-------------|
|
||||||
|
| Startup time | 1.2s | 0.9s | 25% faster |
|
||||||
|
| Large pipeline | 2.5s | 1.8s | 28% faster |
|
||||||
|
| Memory usage | 120MB | 95MB | 21% lower |
|
||||||
|
| Web requests | 450ms | 380ms | 16% faster |
|
||||||
|
|
||||||
|
## Resources
|
||||||
|
|
||||||
|
- [PowerShell 7.5 Release Notes](https://github.com/PowerShell/PowerShell/releases)
|
||||||
|
- [.NET 9 Performance](https://devblogs.microsoft.com/dotnet/performance-improvements-in-net-9)
|
||||||
|
- [PowerShell Team Blog](https://devblogs.microsoft.com/powershell)
|
||||||
1248
skills/powershell-master/SKILL.md
Normal file
1248
skills/powershell-master/SKILL.md
Normal file
File diff suppressed because it is too large
Load Diff
408
skills/powershell-security.md
Normal file
408
skills/powershell-security.md
Normal file
@@ -0,0 +1,408 @@
|
|||||||
|
---
|
||||||
|
name: powershell-security
|
||||||
|
description: Modern PowerShell security practices including SecretManagement, JEA, WDAC, and credential protection
|
||||||
|
---
|
||||||
|
|
||||||
|
# PowerShell Security Best Practices (2025)
|
||||||
|
|
||||||
|
Modern security practices for PowerShell scripts and automation, including credential management, SecretManagement module, and hardening techniques.
|
||||||
|
|
||||||
|
## SecretManagement Module (Recommended 2025 Standard)
|
||||||
|
|
||||||
|
### Overview
|
||||||
|
|
||||||
|
**Microsoft.PowerShell.SecretManagement** is the official solution for secure credential storage in PowerShell.
|
||||||
|
|
||||||
|
**Why use SecretManagement:**
|
||||||
|
- Never store plaintext credentials in scripts
|
||||||
|
- Cross-platform secret storage
|
||||||
|
- Multiple vault provider support
|
||||||
|
- Integration with Azure Key Vault, 1Password, KeePass, etc.
|
||||||
|
|
||||||
|
### Installation
|
||||||
|
|
||||||
|
```powershell
|
||||||
|
# Install SecretManagement module
|
||||||
|
Install-Module -Name Microsoft.PowerShell.SecretManagement -Scope CurrentUser
|
||||||
|
|
||||||
|
# Install vault provider (choose one or more)
|
||||||
|
Install-Module -Name Microsoft.PowerShell.SecretStore # Local encrypted vault
|
||||||
|
Install-Module -Name Az.KeyVault # Azure Key Vault
|
||||||
|
Install-Module -Name SecretManagement.KeePass # KeePass integration
|
||||||
|
```
|
||||||
|
|
||||||
|
### Basic Usage
|
||||||
|
|
||||||
|
```powershell
|
||||||
|
# Register a vault
|
||||||
|
Register-SecretVault -Name LocalVault -ModuleName Microsoft.PowerShell.SecretStore
|
||||||
|
|
||||||
|
# Store a secret
|
||||||
|
$password = Read-Host -AsSecureString -Prompt "Enter password"
|
||||||
|
Set-Secret -Name "DatabasePassword" -Secret $password -Vault LocalVault
|
||||||
|
|
||||||
|
# Retrieve a secret
|
||||||
|
$dbPassword = Get-Secret -Name "DatabasePassword" -Vault LocalVault -AsPlainText
|
||||||
|
# Or as SecureString
|
||||||
|
$dbPasswordSecure = Get-Secret -Name "DatabasePassword" -Vault LocalVault
|
||||||
|
|
||||||
|
# List secrets
|
||||||
|
Get-SecretInfo
|
||||||
|
|
||||||
|
# Remove a secret
|
||||||
|
Remove-Secret -Name "DatabasePassword" -Vault LocalVault
|
||||||
|
```
|
||||||
|
|
||||||
|
### Azure Key Vault Integration
|
||||||
|
|
||||||
|
```powershell
|
||||||
|
# Install and import Az.KeyVault
|
||||||
|
Install-Module -Name Az.KeyVault -Scope CurrentUser
|
||||||
|
Import-Module Az.KeyVault
|
||||||
|
|
||||||
|
# Authenticate to Azure
|
||||||
|
Connect-AzAccount
|
||||||
|
|
||||||
|
# Register Azure Key Vault as secret vault
|
||||||
|
Register-SecretVault -Name AzureKV `
|
||||||
|
-ModuleName Az.KeyVault `
|
||||||
|
-VaultParameters @{
|
||||||
|
AZKVaultName = 'MyKeyVault'
|
||||||
|
SubscriptionId = 'your-subscription-id'
|
||||||
|
}
|
||||||
|
|
||||||
|
# Store secret in Azure Key Vault
|
||||||
|
Set-Secret -Name "ApiKey" -Secret "your-api-key" -Vault AzureKV
|
||||||
|
|
||||||
|
# Retrieve from Azure Key Vault
|
||||||
|
$apiKey = Get-Secret -Name "ApiKey" -Vault AzureKV -AsPlainText
|
||||||
|
```
|
||||||
|
|
||||||
|
### Automation Scripts with SecretManagement
|
||||||
|
|
||||||
|
```powershell
|
||||||
|
<#
|
||||||
|
.SYNOPSIS
|
||||||
|
Secure automation script using SecretManagement
|
||||||
|
|
||||||
|
.DESCRIPTION
|
||||||
|
Demonstrates secure credential handling without hardcoded secrets
|
||||||
|
#>
|
||||||
|
|
||||||
|
#Requires -Modules Microsoft.PowerShell.SecretManagement
|
||||||
|
|
||||||
|
[CmdletBinding()]
|
||||||
|
param()
|
||||||
|
|
||||||
|
# Retrieve credentials from vault
|
||||||
|
$dbConnectionString = Get-Secret -Name "SQLConnectionString" -AsPlainText
|
||||||
|
$apiToken = Get-Secret -Name "APIToken" -AsPlainText
|
||||||
|
|
||||||
|
# Use credentials securely
|
||||||
|
try {
|
||||||
|
# Database operation
|
||||||
|
$connection = New-Object System.Data.SqlClient.SqlConnection($dbConnectionString)
|
||||||
|
$connection.Open()
|
||||||
|
|
||||||
|
# API call with token
|
||||||
|
$headers = @{ Authorization = "Bearer $apiToken" }
|
||||||
|
$response = Invoke-RestMethod -Uri "https://api.example.com/data" -Headers $headers
|
||||||
|
|
||||||
|
# Process results
|
||||||
|
Write-Host "Operation completed successfully"
|
||||||
|
}
|
||||||
|
catch {
|
||||||
|
Write-Error "Operation failed: $_"
|
||||||
|
}
|
||||||
|
finally {
|
||||||
|
if ($connection) { $connection.Close() }
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
## Credential Management Best Practices
|
||||||
|
|
||||||
|
### Never Hardcode Credentials
|
||||||
|
|
||||||
|
```powershell
|
||||||
|
# ❌ WRONG - Hardcoded credentials
|
||||||
|
$password = "MyPassword123"
|
||||||
|
$username = "admin"
|
||||||
|
|
||||||
|
# ❌ WRONG - Plaintext in script
|
||||||
|
$cred = New-Object System.Management.Automation.PSCredential("admin", "password")
|
||||||
|
|
||||||
|
# ✅ CORRECT - SecretManagement
|
||||||
|
$password = Get-Secret -Name "AdminPassword" -AsPlainText
|
||||||
|
$securePassword = ConvertTo-SecureString $password -AsPlainText -Force
|
||||||
|
$cred = New-Object System.Management.Automation.PSCredential("admin", $securePassword)
|
||||||
|
|
||||||
|
# ✅ CORRECT - Interactive prompt (for manual runs)
|
||||||
|
$cred = Get-Credential -Message "Enter admin credentials"
|
||||||
|
|
||||||
|
# ✅ CORRECT - Managed Identity (Azure automation)
|
||||||
|
Connect-AzAccount -Identity
|
||||||
|
```
|
||||||
|
|
||||||
|
### Service Principal Authentication (Azure)
|
||||||
|
|
||||||
|
```powershell
|
||||||
|
# Store service principal credentials in vault
|
||||||
|
Set-Secret -Name "AzureAppId" -Secret "app-id-guid"
|
||||||
|
Set-Secret -Name "AzureAppSecret" -Secret "app-secret-value"
|
||||||
|
Set-Secret -Name "AzureTenantId" -Secret "tenant-id-guid"
|
||||||
|
|
||||||
|
# Retrieve and authenticate
|
||||||
|
$appId = Get-Secret -Name "AzureAppId" -AsPlainText
|
||||||
|
$appSecret = Get-Secret -Name "AzureAppSecret" -AsPlainText
|
||||||
|
$tenantId = Get-Secret -Name "AzureTenantId" -AsPlainText
|
||||||
|
|
||||||
|
$secureSecret = ConvertTo-SecureString $appSecret -AsPlainText -Force
|
||||||
|
$credential = New-Object System.Management.Automation.PSCredential($appId, $secureSecret)
|
||||||
|
|
||||||
|
Connect-AzAccount -ServicePrincipal -Credential $credential -Tenant $tenantId
|
||||||
|
```
|
||||||
|
|
||||||
|
## Just Enough Administration (JEA)
|
||||||
|
|
||||||
|
### What is JEA?
|
||||||
|
|
||||||
|
**Just Enough Administration** restricts PowerShell remoting sessions to specific cmdlets and parameters.
|
||||||
|
|
||||||
|
### Use Cases
|
||||||
|
|
||||||
|
- Delegate admin tasks without full admin rights
|
||||||
|
- Compliance requirements (SOC 2, HIPAA, PCI-DSS)
|
||||||
|
- Production environment hardening
|
||||||
|
- Audit trail for privileged operations
|
||||||
|
|
||||||
|
### Creating a JEA Endpoint
|
||||||
|
|
||||||
|
```powershell
|
||||||
|
# 1. Create role capability file
|
||||||
|
New-PSRoleCapabilityFile -Path "C:\JEA\RestartServices.psrc" `
|
||||||
|
-VisibleCmdlets @{
|
||||||
|
Name = 'Restart-Service'
|
||||||
|
Parameters = @{
|
||||||
|
Name = 'Name'
|
||||||
|
ValidateSet = 'Spooler', 'W32Time', 'WinRM'
|
||||||
|
}
|
||||||
|
}, 'Get-Service'
|
||||||
|
|
||||||
|
# 2. Create session configuration file
|
||||||
|
New-PSSessionConfigurationFile -Path "C:\JEA\RestartServices.pssc" `
|
||||||
|
-SessionType RestrictedRemoteServer `
|
||||||
|
-RoleDefinitions @{
|
||||||
|
'DOMAIN\ServiceAdmins' = @{ RoleCapabilities = 'RestartServices' }
|
||||||
|
} `
|
||||||
|
-LanguageMode NoLanguage
|
||||||
|
|
||||||
|
# 3. Register JEA endpoint
|
||||||
|
Register-PSSessionConfiguration -Name RestartServices `
|
||||||
|
-Path "C:\JEA\RestartServices.pssc" `
|
||||||
|
-Force
|
||||||
|
|
||||||
|
# 4. Connect to JEA endpoint (as delegated user)
|
||||||
|
Enter-PSSession -ComputerName Server01 -ConfigurationName RestartServices
|
||||||
|
|
||||||
|
# User can ONLY run allowed commands
|
||||||
|
Restart-Service -Name Spooler # ✅ Allowed
|
||||||
|
Restart-Service -Name DNS # ❌ Denied (not in ValidateSet)
|
||||||
|
Get-Process # ❌ Denied (not visible)
|
||||||
|
```
|
||||||
|
|
||||||
|
### JEA Audit Logging
|
||||||
|
|
||||||
|
```powershell
|
||||||
|
# Enable transcription and logging
|
||||||
|
New-PSSessionConfigurationFile -Path "C:\JEA\AuditedSession.pssc" `
|
||||||
|
-SessionType RestrictedRemoteServer `
|
||||||
|
-TranscriptDirectory "C:\JEA\Transcripts" `
|
||||||
|
-RunAsVirtualAccount
|
||||||
|
|
||||||
|
# All JEA sessions are transcribed to C:\JEA\Transcripts
|
||||||
|
# Review audit logs
|
||||||
|
Get-ChildItem "C:\JEA\Transcripts" | Get-Content
|
||||||
|
```
|
||||||
|
|
||||||
|
## Windows Defender Application Control (WDAC)
|
||||||
|
|
||||||
|
### PowerShell Script Control
|
||||||
|
|
||||||
|
**WDAC** replaces AppLocker for controlling which PowerShell scripts can execute.
|
||||||
|
|
||||||
|
```powershell
|
||||||
|
# Create WDAC policy for signed scripts only
|
||||||
|
New-CIPolicy -FilePath "C:\WDAC\PowerShellPolicy.xml" `
|
||||||
|
-ScanPath "C:\Scripts" `
|
||||||
|
-Level FilePublisher `
|
||||||
|
-Fallback Hash `
|
||||||
|
-UserPEs
|
||||||
|
|
||||||
|
# Allow only signed scripts
|
||||||
|
Set-RuleOption -FilePath "C:\WDAC\PowerShellPolicy.xml" `
|
||||||
|
-Option 3 # Required WHQL
|
||||||
|
|
||||||
|
# Convert to binary policy
|
||||||
|
ConvertFrom-CIPolicy -XmlFilePath "C:\WDAC\PowerShellPolicy.xml" `
|
||||||
|
-BinaryFilePath "C:\Windows\System32\CodeIntegrity\SIPolicy.p7b"
|
||||||
|
|
||||||
|
# Reboot to apply policy
|
||||||
|
Restart-Computer
|
||||||
|
```
|
||||||
|
|
||||||
|
## Code Signing
|
||||||
|
|
||||||
|
### Why Sign Scripts?
|
||||||
|
|
||||||
|
- Verify script integrity
|
||||||
|
- Meet organizational security policies
|
||||||
|
- Enable WDAC enforcement
|
||||||
|
- Prevent tampering
|
||||||
|
|
||||||
|
### Signing a Script
|
||||||
|
|
||||||
|
```powershell
|
||||||
|
# Get code signing certificate
|
||||||
|
$cert = Get-ChildItem Cert:\CurrentUser\My -CodeSigningCert
|
||||||
|
|
||||||
|
# Sign script
|
||||||
|
Set-AuthenticodeSignature -FilePath "C:\Scripts\MyScript.ps1" -Certificate $cert
|
||||||
|
|
||||||
|
# Verify signature
|
||||||
|
$signature = Get-AuthenticodeSignature -FilePath "C:\Scripts\MyScript.ps1"
|
||||||
|
$signature.Status # Should be "Valid"
|
||||||
|
```
|
||||||
|
|
||||||
|
### Execution Policy
|
||||||
|
|
||||||
|
```powershell
|
||||||
|
# Check current execution policy
|
||||||
|
Get-ExecutionPolicy
|
||||||
|
|
||||||
|
# Set execution policy (requires admin)
|
||||||
|
Set-ExecutionPolicy RemoteSigned -Scope LocalMachine
|
||||||
|
|
||||||
|
# Bypass for single script (testing only)
|
||||||
|
PowerShell.exe -ExecutionPolicy Bypass -File "script.ps1"
|
||||||
|
```
|
||||||
|
|
||||||
|
## Constrained Language Mode
|
||||||
|
|
||||||
|
### What is Constrained Language Mode?
|
||||||
|
|
||||||
|
Restricts PowerShell language features to prevent malicious code execution.
|
||||||
|
|
||||||
|
```powershell
|
||||||
|
# Check current language mode
|
||||||
|
$ExecutionContext.SessionState.LanguageMode
|
||||||
|
# Output: FullLanguage (admin) or ConstrainedLanguage (standard user)
|
||||||
|
|
||||||
|
# Set system-wide constrained language mode
|
||||||
|
# Via Environment Variable or Group Policy
|
||||||
|
# Set: __PSLockdownPolicy = 4
|
||||||
|
|
||||||
|
# Test constrained mode behavior
|
||||||
|
# FullLanguage allows:
|
||||||
|
[System.Net.WebClient]::new() # ✅ Allowed
|
||||||
|
|
||||||
|
# ConstrainedLanguage blocks:
|
||||||
|
[System.Net.WebClient]::new() # ❌ Blocked
|
||||||
|
Add-Type -TypeDefinition "..." # ❌ Blocked
|
||||||
|
```
|
||||||
|
|
||||||
|
## Script Block Logging
|
||||||
|
|
||||||
|
### Enable Logging
|
||||||
|
|
||||||
|
```powershell
|
||||||
|
# Enable via Group Policy or Registry
|
||||||
|
# HKLM:\Software\Policies\Microsoft\Windows\PowerShell\ScriptBlockLogging
|
||||||
|
New-ItemProperty -Path "HKLM:\Software\Policies\Microsoft\Windows\PowerShell\ScriptBlockLogging" `
|
||||||
|
-Name "EnableScriptBlockLogging" -Value 1 -PropertyType DWord
|
||||||
|
|
||||||
|
# Log location: Windows Event Log
|
||||||
|
# Event Viewer > Applications and Services Logs > Microsoft > Windows > PowerShell > Operational
|
||||||
|
```
|
||||||
|
|
||||||
|
### Review Logs
|
||||||
|
|
||||||
|
```powershell
|
||||||
|
# Query script block logs
|
||||||
|
Get-WinEvent -LogName "Microsoft-Windows-PowerShell/Operational" |
|
||||||
|
Where-Object { $_.Id -eq 4104 } | # Script Block Logging event
|
||||||
|
Select-Object TimeCreated, Message |
|
||||||
|
Out-GridView
|
||||||
|
```
|
||||||
|
|
||||||
|
## Input Validation
|
||||||
|
|
||||||
|
### Prevent Injection Attacks
|
||||||
|
|
||||||
|
```powershell
|
||||||
|
# ❌ WRONG - No validation
|
||||||
|
function Get-UserData {
|
||||||
|
param($Username)
|
||||||
|
Invoke-Sqlcmd -Query "SELECT * FROM Users WHERE Username = '$Username'"
|
||||||
|
}
|
||||||
|
# Vulnerable to SQL injection
|
||||||
|
|
||||||
|
# ✅ CORRECT - Parameterized queries
|
||||||
|
function Get-UserData {
|
||||||
|
param(
|
||||||
|
[ValidatePattern('^[a-zA-Z0-9_-]+$')]
|
||||||
|
[string]$Username
|
||||||
|
)
|
||||||
|
Invoke-Sqlcmd -Query "SELECT * FROM Users WHERE Username = @Username" `
|
||||||
|
-Variable @{Username=$Username}
|
||||||
|
}
|
||||||
|
|
||||||
|
# ✅ CORRECT - ValidateSet for known values
|
||||||
|
function Restart-AppService {
|
||||||
|
param(
|
||||||
|
[ValidateSet('Web', 'API', 'Worker')]
|
||||||
|
[string]$ServiceName
|
||||||
|
)
|
||||||
|
Restart-Service -Name "App${ServiceName}Service"
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
## Security Checklist
|
||||||
|
|
||||||
|
### Script Development
|
||||||
|
|
||||||
|
- [ ] Never hardcode credentials (use SecretManagement)
|
||||||
|
- [ ] Use parameterized queries for SQL operations
|
||||||
|
- [ ] Validate all user input with `[ValidatePattern]`, `[ValidateSet]`, etc.
|
||||||
|
- [ ] Enable `Set-StrictMode -Version Latest`
|
||||||
|
- [ ] Use `try/catch` for error handling
|
||||||
|
- [ ] Avoid `Invoke-Expression` with user input
|
||||||
|
- [ ] Sign production scripts
|
||||||
|
- [ ] Enable Script Block Logging
|
||||||
|
|
||||||
|
### Automation
|
||||||
|
|
||||||
|
- [ ] Use Managed Identity or Service Principal (never passwords)
|
||||||
|
- [ ] Store secrets in SecretManagement or Azure Key Vault
|
||||||
|
- [ ] Implement JEA for delegated admin tasks
|
||||||
|
- [ ] Enable audit logging for all privileged operations
|
||||||
|
- [ ] Use least privilege principle
|
||||||
|
- [ ] Rotate credentials regularly
|
||||||
|
- [ ] Monitor failed authentication attempts
|
||||||
|
|
||||||
|
### Production Environments
|
||||||
|
|
||||||
|
- [ ] Implement WDAC policies for script control
|
||||||
|
- [ ] Use Constrained Language Mode for non-admin users
|
||||||
|
- [ ] Enable PowerShell logging (Script Block + Transcription)
|
||||||
|
- [ ] Require signed scripts (via execution policy)
|
||||||
|
- [ ] Regular security audits
|
||||||
|
- [ ] Keep PowerShell updated (7.5+)
|
||||||
|
- [ ] Use JEA for remote administration
|
||||||
|
|
||||||
|
## Resources
|
||||||
|
|
||||||
|
- [SecretManagement Documentation](https://learn.microsoft.com/en-us/powershell/module/microsoft.powershell.secretmanagement)
|
||||||
|
- [JEA Documentation](https://learn.microsoft.com/en-us/powershell/scripting/security/remoting/jea/overview)
|
||||||
|
- [WDAC Documentation](https://learn.microsoft.com/en-us/windows/security/application-security/application-control/windows-defender-application-control)
|
||||||
|
- [PowerShell Security Best Practices](https://learn.microsoft.com/en-us/powershell/scripting/security/securing-powershell)
|
||||||
|
- [Azure Key Vault](https://learn.microsoft.com/en-us/azure/key-vault/)
|
||||||
470
skills/powershell-shell-detection.md
Normal file
470
skills/powershell-shell-detection.md
Normal file
@@ -0,0 +1,470 @@
|
|||||||
|
---
|
||||||
|
name: powershell-shell-detection
|
||||||
|
description: Shell detection and cross-shell compatibility guidance for PowerShell vs Git Bash/MSYS2 on Windows
|
||||||
|
---
|
||||||
|
|
||||||
|
# PowerShell Shell Detection & Cross-Shell Compatibility
|
||||||
|
|
||||||
|
Critical guidance for distinguishing between PowerShell and Git Bash/MSYS2 shells on Windows, with shell-specific path handling and compatibility notes.
|
||||||
|
|
||||||
|
## Shell Detection Priority (Windows)
|
||||||
|
|
||||||
|
When working on Windows, correctly identifying the shell environment is crucial for proper path handling and command execution.
|
||||||
|
|
||||||
|
### Detection Order (Most Reliable First)
|
||||||
|
|
||||||
|
1. **process.env.PSModulePath** (PowerShell specific)
|
||||||
|
2. **process.env.MSYSTEM** (Git Bash/MinGW specific)
|
||||||
|
3. **process.env.WSL_DISTRO_NAME** (WSL specific)
|
||||||
|
4. **uname -s output** (Cross-shell, requires execution)
|
||||||
|
|
||||||
|
## PowerShell Detection
|
||||||
|
|
||||||
|
### Primary Indicators
|
||||||
|
|
||||||
|
**PSModulePath (Most Reliable):**
|
||||||
|
```powershell
|
||||||
|
# PowerShell detection
|
||||||
|
if ($env:PSModulePath) {
|
||||||
|
Write-Host "Running in PowerShell"
|
||||||
|
# PSModulePath contains 3+ paths separated by semicolons
|
||||||
|
$env:PSModulePath -split ';'
|
||||||
|
}
|
||||||
|
|
||||||
|
# Check PowerShell version
|
||||||
|
$PSVersionTable.PSVersion
|
||||||
|
# Output: 7.5.4 (PowerShell 7) or 5.1.x (Windows PowerShell)
|
||||||
|
```
|
||||||
|
|
||||||
|
**PowerShell-Specific Variables:**
|
||||||
|
```powershell
|
||||||
|
# These only exist in PowerShell
|
||||||
|
$PSVersionTable # Version info
|
||||||
|
$PSScriptRoot # Script directory
|
||||||
|
$PSCommandPath # Script full path
|
||||||
|
$IsWindows # Platform detection (PS 7+)
|
||||||
|
$IsLinux # Platform detection (PS 7+)
|
||||||
|
$IsMacOS # Platform detection (PS 7+)
|
||||||
|
```
|
||||||
|
|
||||||
|
### Shell Type Detection in Scripts
|
||||||
|
|
||||||
|
```powershell
|
||||||
|
function Get-ShellType {
|
||||||
|
if ($PSVersionTable) {
|
||||||
|
return "PowerShell $($PSVersionTable.PSVersion)"
|
||||||
|
}
|
||||||
|
elseif ($env:PSModulePath -and ($env:PSModulePath -split ';').Count -ge 3) {
|
||||||
|
return "PowerShell (detected via PSModulePath)"
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
return "Not PowerShell"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Get-ShellType
|
||||||
|
```
|
||||||
|
|
||||||
|
## Git Bash / MSYS2 Detection
|
||||||
|
|
||||||
|
### Primary Indicators
|
||||||
|
|
||||||
|
**MSYSTEM Environment Variable (Most Reliable):**
|
||||||
|
```bash
|
||||||
|
# Bash detection in Git Bash/MSYS2
|
||||||
|
if [ -n "$MSYSTEM" ]; then
|
||||||
|
echo "Running in Git Bash/MSYS2: $MSYSTEM"
|
||||||
|
fi
|
||||||
|
|
||||||
|
# MSYSTEM values:
|
||||||
|
# MINGW64 - Native Windows 64-bit environment
|
||||||
|
# MINGW32 - Native Windows 32-bit environment
|
||||||
|
# MSYS - POSIX-compliant build environment
|
||||||
|
```
|
||||||
|
|
||||||
|
**Secondary Detection Methods:**
|
||||||
|
```bash
|
||||||
|
# Using OSTYPE (Bash-specific)
|
||||||
|
case "$OSTYPE" in
|
||||||
|
msys*) echo "MSYS/Git Bash" ;;
|
||||||
|
cygwin*) echo "Cygwin" ;;
|
||||||
|
linux*) echo "Linux" ;;
|
||||||
|
darwin*) echo "macOS" ;;
|
||||||
|
esac
|
||||||
|
|
||||||
|
# Using uname (Most portable)
|
||||||
|
case "$(uname -s)" in
|
||||||
|
MINGW64*) echo "Git Bash 64-bit" ;;
|
||||||
|
MINGW32*) echo "Git Bash 32-bit" ;;
|
||||||
|
MSYS*) echo "MSYS" ;;
|
||||||
|
CYGWIN*) echo "Cygwin" ;;
|
||||||
|
Linux*) echo "Linux" ;;
|
||||||
|
Darwin*) echo "macOS" ;;
|
||||||
|
esac
|
||||||
|
```
|
||||||
|
|
||||||
|
## Cross-Shell Compatibility on Windows
|
||||||
|
|
||||||
|
### Critical Differences
|
||||||
|
|
||||||
|
| Aspect | PowerShell | Git Bash/MSYS2 |
|
||||||
|
|--------|-----------|----------------|
|
||||||
|
| **Environment Variable** | `$env:VARIABLE` | `$VARIABLE` |
|
||||||
|
| **Path Separator** | `;` (semicolon) | `:` (colon) |
|
||||||
|
| **Path Style** | `C:\Windows\System32` | `/c/Windows/System32` |
|
||||||
|
| **Home Directory** | `$env:USERPROFILE` | `$HOME` |
|
||||||
|
| **Temp Directory** | `$env:TEMP` | `/tmp` |
|
||||||
|
| **Command Format** | `Get-ChildItem` | `ls` (native command) |
|
||||||
|
| **Aliases** | PowerShell cmdlet aliases | Unix command aliases |
|
||||||
|
|
||||||
|
### Path Handling: PowerShell vs Git Bash
|
||||||
|
|
||||||
|
**PowerShell Path Handling:**
|
||||||
|
```powershell
|
||||||
|
# Native Windows paths work directly
|
||||||
|
$path = "C:\Users\John\Documents"
|
||||||
|
Test-Path $path # True
|
||||||
|
|
||||||
|
# Forward slashes also work in PowerShell 7+
|
||||||
|
$path = "C:/Users/John/Documents"
|
||||||
|
Test-Path $path # True
|
||||||
|
|
||||||
|
# Use Join-Path for cross-platform compatibility
|
||||||
|
$configPath = Join-Path -Path $PSScriptRoot -ChildPath "config.json"
|
||||||
|
|
||||||
|
# Use [System.IO.Path] for advanced scenarios
|
||||||
|
$fullPath = [System.IO.Path]::Combine($home, "documents", "file.txt")
|
||||||
|
```
|
||||||
|
|
||||||
|
**Git Bash Path Handling:**
|
||||||
|
```bash
|
||||||
|
# Git Bash uses Unix-style paths
|
||||||
|
path="/c/Users/John/Documents"
|
||||||
|
test -d "$path" && echo "Directory exists"
|
||||||
|
|
||||||
|
# Automatic path conversion (CAUTION)
|
||||||
|
# Git Bash converts Unix-style paths to Windows-style
|
||||||
|
# /c/Users → C:\Users (automatic)
|
||||||
|
# Arguments starting with / may be converted unexpectedly
|
||||||
|
|
||||||
|
# Use cygpath for manual conversion
|
||||||
|
cygpath -u "C:\path" # → /c/path (Unix format)
|
||||||
|
cygpath -w "/c/path" # → C:\path (Windows format)
|
||||||
|
cygpath -m "/c/path" # → C:/path (Mixed format)
|
||||||
|
```
|
||||||
|
|
||||||
|
## Automatic Path Conversion in Git Bash (CRITICAL)
|
||||||
|
|
||||||
|
Git Bash/MSYS2 automatically converts paths in certain scenarios, which can cause issues:
|
||||||
|
|
||||||
|
### What Triggers Conversion
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# Leading forward slash triggers conversion
|
||||||
|
command /foo # Converts to C:\msys64\foo
|
||||||
|
|
||||||
|
# Path lists with colons
|
||||||
|
export PATH=/foo:/bar # Converts to C:\msys64\foo;C:\msys64\bar
|
||||||
|
|
||||||
|
# Arguments after dashes
|
||||||
|
command --path=/foo # Converts to --path=C:\msys64\foo
|
||||||
|
```
|
||||||
|
|
||||||
|
### What's Exempt from Conversion
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# Arguments with equals sign (variable assignments)
|
||||||
|
VAR=/foo command # NOT converted
|
||||||
|
|
||||||
|
# Drive specifiers
|
||||||
|
command C:/path # NOT converted
|
||||||
|
|
||||||
|
# Arguments with semicolons (already Windows format)
|
||||||
|
command "C:\foo;D:\bar" # NOT converted
|
||||||
|
|
||||||
|
# Double slashes (Windows switches)
|
||||||
|
command //e //s # NOT converted
|
||||||
|
```
|
||||||
|
|
||||||
|
### Disabling Path Conversion
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# Disable ALL conversion (Git Bash)
|
||||||
|
export MSYS_NO_PATHCONV=1
|
||||||
|
command /foo # Stays as /foo
|
||||||
|
|
||||||
|
# Exclude specific patterns (MSYS2)
|
||||||
|
export MSYS2_ARG_CONV_EXCL="*" # Exclude everything
|
||||||
|
export MSYS2_ARG_CONV_EXCL="--dir=;/test" # Specific prefixes
|
||||||
|
```
|
||||||
|
|
||||||
|
## When to Use PowerShell vs Git Bash on Windows
|
||||||
|
|
||||||
|
### Use PowerShell When:
|
||||||
|
|
||||||
|
- ✅ **Windows-specific tasks** - Registry, WMI, Windows services
|
||||||
|
- ✅ **Azure/Microsoft 365 automation** - Az, Microsoft.Graph modules
|
||||||
|
- ✅ **Module ecosystem** - Leverage PSGallery modules
|
||||||
|
- ✅ **Object-oriented pipelines** - Rich object manipulation
|
||||||
|
- ✅ **Native Windows integration** - Built into Windows
|
||||||
|
- ✅ **CI/CD with pwsh** - GitHub Actions, Azure DevOps
|
||||||
|
- ✅ **Cross-platform scripting** - PowerShell 7 works on Linux/macOS
|
||||||
|
|
||||||
|
**Example PowerShell Scenario:**
|
||||||
|
```powershell
|
||||||
|
# Azure VM management with Az module
|
||||||
|
Connect-AzAccount
|
||||||
|
Get-AzVM -ResourceGroupName "Production" |
|
||||||
|
Where-Object {$_.PowerState -eq "VM running"} |
|
||||||
|
Stop-AzVM -Force
|
||||||
|
```
|
||||||
|
|
||||||
|
### Use Git Bash When:
|
||||||
|
|
||||||
|
- ✅ **Unix tool compatibility** - sed, awk, grep, find
|
||||||
|
- ✅ **Git operations** - Native Git command-line experience
|
||||||
|
- ✅ **POSIX script execution** - Running Linux shell scripts
|
||||||
|
- ✅ **Cross-platform shell scripts** - Bash scripts from Linux/macOS
|
||||||
|
- ✅ **Text processing** - Unix text utilities (sed, awk, cut)
|
||||||
|
- ✅ **Development workflows** - Node.js, Python, Ruby with Unix tools
|
||||||
|
|
||||||
|
**Example Git Bash Scenario:**
|
||||||
|
```bash
|
||||||
|
# Git workflow with Unix tools
|
||||||
|
git log --oneline | grep -i "feature" | awk '{print $1}' |
|
||||||
|
xargs git show --stat
|
||||||
|
```
|
||||||
|
|
||||||
|
## Shell-Aware Script Design
|
||||||
|
|
||||||
|
### Detect and Adapt (PowerShell)
|
||||||
|
|
||||||
|
```powershell
|
||||||
|
# Detect if running in PowerShell or Git Bash context
|
||||||
|
function Test-PowerShellContext {
|
||||||
|
return ($null -ne $PSVersionTable)
|
||||||
|
}
|
||||||
|
|
||||||
|
# Adapt path handling based on context
|
||||||
|
function Get-CrossPlatformPath {
|
||||||
|
param([string]$Path)
|
||||||
|
|
||||||
|
if (Test-PowerShellContext) {
|
||||||
|
# PowerShell: Use Join-Path
|
||||||
|
return (Resolve-Path $Path -ErrorAction SilentlyContinue).Path
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
# Non-PowerShell context
|
||||||
|
Write-Warning "Not running in PowerShell. Path operations may differ."
|
||||||
|
return $Path
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
### Detect and Adapt (Bash)
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# Detect shell environment
|
||||||
|
detect_shell() {
|
||||||
|
if [ -n "$MSYSTEM" ]; then
|
||||||
|
echo "git-bash"
|
||||||
|
elif [ -n "$PSModulePath" ]; then
|
||||||
|
echo "powershell"
|
||||||
|
elif [ -n "$WSL_DISTRO_NAME" ]; then
|
||||||
|
echo "wsl"
|
||||||
|
else
|
||||||
|
echo "unix"
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
|
||||||
|
# Adapt path handling
|
||||||
|
convert_path() {
|
||||||
|
local path="$1"
|
||||||
|
local shell_type=$(detect_shell)
|
||||||
|
|
||||||
|
case "$shell_type" in
|
||||||
|
git-bash)
|
||||||
|
# Convert Windows path to Unix style
|
||||||
|
echo "$path" | sed 's|\\|/|g' | sed 's|^\([A-Z]\):|/\L\1|'
|
||||||
|
;;
|
||||||
|
*)
|
||||||
|
echo "$path"
|
||||||
|
;;
|
||||||
|
esac
|
||||||
|
}
|
||||||
|
|
||||||
|
# Usage
|
||||||
|
shell_type=$(detect_shell)
|
||||||
|
echo "Running in: $shell_type"
|
||||||
|
```
|
||||||
|
|
||||||
|
## Environment Variable Comparison
|
||||||
|
|
||||||
|
### Common Environment Variables
|
||||||
|
|
||||||
|
| Variable | PowerShell | Git Bash | Purpose |
|
||||||
|
|----------|-----------|----------|---------|
|
||||||
|
| **Username** | `$env:USERNAME` | `$USER` | Current user |
|
||||||
|
| **Home Directory** | `$env:USERPROFILE` | `$HOME` | User home |
|
||||||
|
| **Temp Directory** | `$env:TEMP` | `/tmp` | Temporary files |
|
||||||
|
| **Path List** | `$env:Path` (`;` sep) | `$PATH` (`:` sep) | Executable paths |
|
||||||
|
| **Shell Detection** | `$env:PSModulePath` | `$MSYSTEM` | Shell identifier |
|
||||||
|
|
||||||
|
### Cross-Shell Variable Access
|
||||||
|
|
||||||
|
**PowerShell accessing environment variables:**
|
||||||
|
```powershell
|
||||||
|
$env:PATH # Current PATH
|
||||||
|
$env:PSModulePath # PowerShell module paths
|
||||||
|
$env:MSYSTEM # Would be empty in PowerShell
|
||||||
|
[Environment]::GetEnvironmentVariable("PATH", "Machine") # System PATH
|
||||||
|
```
|
||||||
|
|
||||||
|
**Git Bash accessing environment variables:**
|
||||||
|
```bash
|
||||||
|
echo $PATH # Current PATH
|
||||||
|
echo $MSYSTEM # Git Bash: MINGW64, MINGW32, or MSYS
|
||||||
|
echo $PSModulePath # Would be empty in pure Bash
|
||||||
|
```
|
||||||
|
|
||||||
|
## Practical Examples
|
||||||
|
|
||||||
|
### Example 1: Cross-Shell File Finding
|
||||||
|
|
||||||
|
**PowerShell:**
|
||||||
|
```powershell
|
||||||
|
# Find files modified in last 7 days
|
||||||
|
Get-ChildItem -Path "C:\Projects" -Recurse -File |
|
||||||
|
Where-Object { $_.LastWriteTime -gt (Get-Date).AddDays(-7) } |
|
||||||
|
Select-Object FullName, LastWriteTime
|
||||||
|
```
|
||||||
|
|
||||||
|
**Git Bash:**
|
||||||
|
```bash
|
||||||
|
# Same operation in Git Bash
|
||||||
|
find /c/Projects -type f -mtime -7 -exec ls -lh {} \;
|
||||||
|
```
|
||||||
|
|
||||||
|
### Example 2: Process Management
|
||||||
|
|
||||||
|
**PowerShell:**
|
||||||
|
```powershell
|
||||||
|
# Stop all Chrome processes
|
||||||
|
Get-Process chrome -ErrorAction SilentlyContinue | Stop-Process -Force
|
||||||
|
```
|
||||||
|
|
||||||
|
**Git Bash:**
|
||||||
|
```bash
|
||||||
|
# Same operation in Git Bash
|
||||||
|
ps aux | grep chrome | awk '{print $2}' | xargs kill -9 2>/dev/null
|
||||||
|
```
|
||||||
|
|
||||||
|
### Example 3: Text File Processing
|
||||||
|
|
||||||
|
**PowerShell:**
|
||||||
|
```powershell
|
||||||
|
# Extract unique email addresses from logs
|
||||||
|
Get-Content "logs.txt" |
|
||||||
|
Select-String -Pattern '\b[A-Za-z0-9._%+-]+@[A-Za-z0-9.-]+\.[A-Z|a-z]{2,}\b' |
|
||||||
|
ForEach-Object { $_.Matches.Value } |
|
||||||
|
Sort-Object -Unique
|
||||||
|
```
|
||||||
|
|
||||||
|
**Git Bash:**
|
||||||
|
```bash
|
||||||
|
# Same operation in Git Bash
|
||||||
|
grep -oE '\b[A-Za-z0-9._%+-]+@[A-Za-z0-9.-]+\.[A-Z|a-z]{2,}\b' logs.txt |
|
||||||
|
sort -u
|
||||||
|
```
|
||||||
|
|
||||||
|
## Troubleshooting Cross-Shell Issues
|
||||||
|
|
||||||
|
### Issue 1: Command Not Found
|
||||||
|
|
||||||
|
**Problem:** Command works in one shell but not another
|
||||||
|
```powershell
|
||||||
|
# PowerShell
|
||||||
|
Get-Process # Works
|
||||||
|
```
|
||||||
|
```bash
|
||||||
|
# Git Bash
|
||||||
|
Get-Process # Command not found
|
||||||
|
```
|
||||||
|
|
||||||
|
**Solution:** Understand that PowerShell cmdlets don't exist in Bash. Use native commands or install PowerShell Core (pwsh) in Git Bash:
|
||||||
|
```bash
|
||||||
|
# Run PowerShell from Git Bash
|
||||||
|
pwsh -Command "Get-Process"
|
||||||
|
```
|
||||||
|
|
||||||
|
### Issue 2: Path Format Mismatches
|
||||||
|
|
||||||
|
**Problem:** Paths don't work across shells
|
||||||
|
```bash
|
||||||
|
# Git Bash path
|
||||||
|
/c/Users/John/file.txt # Works in Bash
|
||||||
|
|
||||||
|
# PowerShell
|
||||||
|
Test-Path "/c/Users/John/file.txt" # May fail
|
||||||
|
```
|
||||||
|
|
||||||
|
**Solution:** Use cygpath for conversion or normalize paths:
|
||||||
|
```bash
|
||||||
|
# Convert to Windows format for PowerShell
|
||||||
|
win_path=$(cygpath -w "/c/Users/John/file.txt")
|
||||||
|
pwsh -Command "Test-Path '$win_path'"
|
||||||
|
```
|
||||||
|
|
||||||
|
### Issue 3: Alias Conflicts
|
||||||
|
|
||||||
|
**Problem:** `ls`, `cd`, `cat` behave differently
|
||||||
|
```powershell
|
||||||
|
# PowerShell
|
||||||
|
ls # Actually runs Get-ChildItem
|
||||||
|
```
|
||||||
|
```bash
|
||||||
|
# Git Bash
|
||||||
|
ls # Runs native Unix ls command
|
||||||
|
```
|
||||||
|
|
||||||
|
**Solution:** Use full cmdlet names in PowerShell scripts:
|
||||||
|
```powershell
|
||||||
|
# Instead of: ls
|
||||||
|
Get-ChildItem # Explicit cmdlet name
|
||||||
|
```
|
||||||
|
|
||||||
|
## Best Practices Summary
|
||||||
|
|
||||||
|
### PowerShell Scripts
|
||||||
|
1. ✅ Use `$PSScriptRoot` for script-relative paths
|
||||||
|
2. ✅ Use `Join-Path` or `[IO.Path]::Combine()` for paths
|
||||||
|
3. ✅ Avoid hardcoded backslashes
|
||||||
|
4. ✅ Use full cmdlet names (no aliases)
|
||||||
|
5. ✅ Test on all target platforms
|
||||||
|
6. ✅ Use `$IsWindows`, `$IsLinux`, `$IsMacOS` for platform detection
|
||||||
|
|
||||||
|
### Git Bash Scripts
|
||||||
|
1. ✅ Check `$MSYSTEM` for Git Bash detection
|
||||||
|
2. ✅ Use `cygpath` for path conversion when needed
|
||||||
|
3. ✅ Set `MSYS_NO_PATHCONV=1` to disable auto-conversion if needed
|
||||||
|
4. ✅ Quote paths with spaces
|
||||||
|
5. ✅ Use Unix-style paths (`/c/...`) within Bash
|
||||||
|
6. ✅ Convert to Windows paths when calling Windows tools
|
||||||
|
|
||||||
|
### Cross-Shell Development
|
||||||
|
1. ✅ Document which shell your script requires
|
||||||
|
2. ✅ Add shell detection at script start
|
||||||
|
3. ✅ Provide clear error messages for wrong shell
|
||||||
|
4. ✅ Consider creating wrapper scripts for cross-shell compatibility
|
||||||
|
5. ✅ Test in both PowerShell and Git Bash if supporting both
|
||||||
|
|
||||||
|
## Resources
|
||||||
|
|
||||||
|
- [PowerShell Documentation](https://learn.microsoft.com/powershell)
|
||||||
|
- [Git for Windows Documentation](https://git-scm.com/doc)
|
||||||
|
- [MSYS2 Documentation](https://www.msys2.org/docs/what-is-msys2/)
|
||||||
|
- [Cygpath Documentation](https://www.cygwin.com/cygwin-ug-net/cygpath.html)
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
**Last Updated:** October 2025
|
||||||
Reference in New Issue
Block a user