From f97d4fae1b47569596fe437c7a07328876f034f9 Mon Sep 17 00:00:00 2001 From: Robert Good Date: Fri, 16 Oct 2026 10:51:32 -0700 Subject: [PATCH 1/4] KV ACL Set --- .../key-vault/Set-AzKeyVaultAclGroup.ps1 | 162 ++++++++++++++++++ 1 file changed, 162 insertions(+) create mode 100644 scripts/azure-resources/key-vault/Set-AzKeyVaultAclGroup.ps1 diff --git a/scripts/azure-resources/key-vault/Set-AzKeyVaultAclGroup.ps1 b/scripts/azure-resources/key-vault/Set-AzKeyVaultAclGroup.ps1 new file mode 100644 index 0000000..1fc9168 --- /dev/null +++ b/scripts/azure-resources/key-vault/Set-AzKeyVaultAclGroup.ps1 @@ -0,0 +1,162 @@ +#----------------------------------------------------------------------- +# Set-AzKeyVaultAclGroup [-Group ] [-KeyVault ] [-WhatIf] +# +# Grants one or more Entra ID security groups ALL key/secret/certificate +# permissions on legacy Access Policy (non-RBAC) Key Vaults in a subscription. +# Does az login, lets the user pick a subscription from a UI list. +# +# -Group Group display names or object IDs (GUIDs). +# -KeyVault Optional. Vault names to limit to. Default: every access-policy vault in the subscription. +# +# Example: .\Set-AzKeyVaultAclGroup.ps1 -Group "Cloud Engineers" +# -Template Portal-style permission template (default 'All'): Key Management, Secret Management, +# Certificate Management, Key & Secret Management, Secret & Certificate Management, +# Key, Secret, & Certificate Management, SQL Server Connector, +# Azure Data Lake Storage or Azure Storage, Azure Backup, Exchange Online Customer Key, +# SharePoint Online Customer Key, Azure Information BYOK +# -KeyPermissions / -SecretPermissions / -CertificatePermissions +# Override the template for that category (e.g. -SecretPermissions get,list). @() grants none. +# +# Example: .\Set-AzKeyVaultAclGroup.ps1 -Group "Cloud Engineers" -KeyVault kv-devtest-myproduct-001,kv-devtest-myplatform-001 +# Example: .\Set-AzKeyVaultAclGroup.ps1 -Group "Cloud Engineers" -Template "Secret Management" +# Example: .\Set-AzKeyVaultAclGroup.ps1 -Group "Cloud Engineers" -Template "All" -KeyPermissions get,list +#----------------------------------------------------------------------- +[CmdletBinding(SupportsShouldProcess)] +param +( + [Parameter(Mandatory)][string[]] $Group, + [string[]] $KeyVault, + [ValidateSet('All','Key Management','Secret Management','Certificate Management', + 'Key & Secret Management','Secret & Certificate Management','Key, Secret, & Certificate Management', + 'SQL Server Connector','Azure Data Lake Storage or Azure Storage','Azure Backup', + 'Exchange Online Customer Key','SharePoint Online Customer Key','Azure Information BYOK')] + [string] $Template = 'All', + # Explicit lists override the template for that category. Use @() to grant none. + [string[]] $KeyPermissions, + [string[]] $SecretPermissions, + [string[]] $CertificatePermissions +) + +$ErrorActionPreference = 'Stop' + +# Same permission sets as the Azure portal access policy templates +$allKey = 'get','list','update','create','import','delete','recover','backup','restore','purge', + 'decrypt','encrypt','unwrapKey','wrapKey','verify','sign','release','rotate','getrotationpolicy','setrotationpolicy' +$allSecret = 'get','list','set','delete','recover','backup','restore','purge' +$allCert = 'get','list','update','create','import','delete','recover','backup','restore', + 'managecontacts','manageissuers','getissuers','listissuers','setissuers','deleteissuers','purge' +$mgmtKey = 'get','list','update','create','import','delete','recover','backup','restore','rotate','getrotationpolicy','setrotationpolicy','purge' +$mgmtSecret = 'get','list','set','delete','recover','backup','restore','purge' +$mgmtCert = 'get','list','update','create','import','delete','recover','backup','restore', + 'managecontacts','manageissuers','getissuers','listissuers','setissuers','deleteissuers','purge' + +$templates = @{ + 'All' = @{ Key = $allKey; Secret = $allSecret; Cert = $allCert } + 'Key Management' = @{ Key = $mgmtKey; Secret = @(); Cert = @() } + 'Secret Management' = @{ Key = @(); Secret = $mgmtSecret; Cert = @() } + 'Certificate Management' = @{ Key = @(); Secret = @(); Cert = $mgmtCert } + 'Key & Secret Management' = @{ Key = $mgmtKey; Secret = $mgmtSecret; Cert = @() } + 'Secret & Certificate Management' = @{ Key = @(); Secret = $mgmtSecret; Cert = $mgmtCert } + 'Key, Secret, & Certificate Management' = @{ Key = $mgmtKey; Secret = $mgmtSecret; Cert = $mgmtCert } + 'SQL Server Connector' = @{ Key = 'get','list','wrapKey','unwrapKey'; Secret = @(); Cert = @() } + 'Azure Data Lake Storage or Azure Storage' = @{ Key = 'get','list','unwrapKey'; Secret = @(); Cert = @() } + 'Azure Backup' = @{ Key = 'get','list','backup'; Secret = 'get','list','backup'; Cert = @() } + 'Exchange Online Customer Key' = @{ Key = 'get','create','delete','list','update','unwrapKey','wrapKey'; Secret = @(); Cert = @() } + 'SharePoint Online Customer Key' = @{ Key = 'get','list','wrapKey','unwrapKey'; Secret = @(); Cert = @() } + 'Azure Information BYOK' = @{ Key = 'get','decrypt','sign'; Secret = @(); Cert = @() } +} +$t = $templates[$Template] +if (-not $PSBoundParameters.ContainsKey('KeyPermissions')) { $KeyPermissions = $t.Key } +if (-not $PSBoundParameters.ContainsKey('SecretPermissions')) { $SecretPermissions = $t.Secret } +if (-not $PSBoundParameters.ContainsKey('CertificatePermissions')) { $CertificatePermissions = $t.Cert } + +$permArgs = @() +if ($KeyPermissions) { $permArgs += '--key-permissions'; $permArgs += $KeyPermissions } +if ($SecretPermissions) { $permArgs += '--secret-permissions'; $permArgs += $SecretPermissions } +if ($CertificatePermissions) { $permArgs += '--certificate-permissions'; $permArgs += $CertificatePermissions } +if (-not $permArgs) { throw 'No permissions selected.' } +Write-Host "Template: $Template" +Write-Host "Keys: $($KeyPermissions -join ',') | Secrets: $($SecretPermissions -join ',') | Certs: $($CertificatePermissions -join ',')" + +# A corrupt/locked extension folder in ~/.azure breaks every az command; use a clean one. +# Only core commands are needed here, so no extensions are required. +$env:AZURE_EXTENSION_DIR = Join-Path $env:TEMP 'az-clean-extensions' +New-Item -ItemType Directory -Force -Path $env:AZURE_EXTENSION_DIR | Out-Null + +function Invoke-Az { + $errFile = New-TemporaryFile + try { + $out = & az @args 2>$errFile + if ($LASTEXITCODE -ne 0) { throw ((Get-Content $errFile -Raw) + ($out | Out-String)) } + $out + } finally { Remove-Item $errFile -ErrorAction SilentlyContinue } +} + +# *** +# *** Auth + subscription selection +# *** +Write-Host '*** Login ***' +Invoke-Az login --only-show-errors | Out-Null + +$subs = @(Invoke-Az account list --query "[?state=='Enabled']" -o json | ConvertFrom-Json) +if (-not $subs) { throw 'No enabled subscriptions found.' } + +$choice = $null +if (Get-Command Out-GridView -ErrorAction SilentlyContinue) { + $choice = $subs | Select-Object name, id, tenantId | + Out-GridView -Title 'Select a subscription' -OutputMode Single +} else { + for ($i = 0; $i -lt $subs.Count; $i++) { Write-Host "[$i] $($subs[$i].name) ($($subs[$i].id))" } + $idx = Read-Host 'Select subscription number' + $choice = $subs[[int]$idx] +} +if (-not $choice) { throw 'No subscription selected.' } +Invoke-Az account set --subscription $choice.id | Out-Null +Write-Host "Subscription: $($choice.name)" + +# *** +# *** Resolve groups to object IDs +# *** +$groupIds = foreach ($g in $Group) { + if ($g -match '^[0-9a-fA-F]{8}(-[0-9a-fA-F]{4}){3}-[0-9a-fA-F]{12}$') { $g; continue } + $found = @(Invoke-Az ad group list --display-name $g --query '[].id' -o json | ConvertFrom-Json) + if (-not $found) { throw "Group not found: $g" } + if ($found.Count -gt 1) { throw "Multiple groups named '$g'. Use the object ID." } + $found[0] +} + +# *** +# *** Select vaults +# *** +$vaults = @(Invoke-Az keyvault list --query '[].{name:name,rg:resourceGroup}' -o json | ConvertFrom-Json) +if ($KeyVault) { + $missing = $KeyVault | Where-Object { $_ -notin $vaults.name } + foreach ($m in $missing) { Write-Warning "SKIP (not in this subscription): $m" } + $vaults = @($vaults | Where-Object { $_.name -in $KeyVault }) + if (-not $vaults) { Write-Warning 'None of the requested vaults exist in this subscription.'; return } +} + +# *** +# *** Apply +# *** +$results = foreach ($v in $vaults) { + $rbac = Invoke-Az keyvault show --name $v.name --resource-group $v.rg --query 'properties.enableRbacAuthorization' -o tsv + if ($rbac -eq 'true') { + Write-Host "SKIP (RBAC): $($v.name)" + [pscustomobject]@{ Vault = $v.name; Group = '-'; Status = 'Skipped (RBAC)' } + continue + } + foreach ($id in $groupIds) { + $status = 'OK' + if ($PSCmdlet.ShouldProcess("$($v.name)", "Grant all permissions to $id")) { + try { + Invoke-Az keyvault set-policy --name $v.name --resource-group $v.rg --object-id $id @permArgs -o none | Out-Null + } catch { $status = "FAILED: $($_.Exception.Message.Trim())" } + } else { $status = 'WhatIf' } + Write-Host "$($v.name) <- $id : $status" + [pscustomobject]@{ Vault = $v.name; Group = $id; Status = $status } + } +} + +Write-Host '*** Summary ***' +$results | Format-Table -AutoSize From 965966ba3ebd6a9c021e24f935b4f4542a8e6284 Mon Sep 17 00:00:00 2001 From: Robert Good Date: Fri, 16 Oct 2026 11:33:08 -0700 Subject: [PATCH 2/4] repo cleanup --- System.psm1 | 1500 ----------------- scripts/azure-resources/System.psm1 | 1500 ----------------- .../key-vault/Set-AzKeyVaultPolicy.ps1 | 43 - 3 files changed, 3043 deletions(-) delete mode 100644 System.psm1 delete mode 100644 scripts/azure-resources/System.psm1 delete mode 100644 scripts/azure-resources/key-vault/Set-AzKeyVaultPolicy.ps1 diff --git a/System.psm1 b/System.psm1 deleted file mode 100644 index c9cafd5..0000000 --- a/System.psm1 +++ /dev/null @@ -1,1500 +0,0 @@ -#----------------------------------------------------------------------- -# Add-Prefix [-String []] -# -# Example: .\Add-Prefix -String ello -Add H -# Result: Hello -#----------------------------------------------------------------------- -function Add-Prefix -{ - param ( - [Parameter(Mandatory=$true,ValueFromPipelineByPropertyName=$true)] - [string]$String = $(throw '-String is a required parameter.'), - [Parameter(Mandatory=$true,ValueFromPipelineByPropertyName=$true)] - [string]$Add = $(throw '-Add is a required parameter.') - ) - Write-Verbose "Add-Prefix -String $String -Add $Add" - [string]$ReturnValue = $String - if (-not (Compare-IsFirst -String $String -BeginsWith $Add)) - { - $ReturnValue = ($Add + $ReturnValue) - Write-Verbose "[Success] 1 items affected. $(Get-CurrentFile) at $(Get-CurrentLine)." - } - else - { - Write-Verbose "[OK] 0 items affected. $(Get-CurrentFile) at $(Get-CurrentLine). -String $String already has prefix of -Add $Add" - } - return $ReturnValue -} -export-modulemember -function Add-Prefix - -#----------------------------------------------------------------------- -# Add-Suffix [-String []] -# -# Example: .\Add-Suffix -String Hell -Add o -# Result: Hello -#----------------------------------------------------------------------- -function Add-Suffix -{ - param ( - [Parameter(Mandatory=$true,ValueFromPipelineByPropertyName=$true)] - [string]$String = $(throw '-String is a required parameter.'), - [Parameter(Mandatory=$true,ValueFromPipelineByPropertyName=$true)] - [string]$Add = $(throw '-Add is a required parameter.') - ) - Write-Verbose "Add-Suffix -String $String -Add $Add" - [string]$ReturnValue = $String - if (-not (Compare-IsLast -String $String -EndsWith $Add)) - { - $ReturnValue = ($String + $Add) - Write-Verbose "[Success] 1 items affected. $(Get-CurrentFile) at $(Get-CurrentLine)." - } - else - { - Write-Verbose "[OK] 0 items affected. $(Get-CurrentFile) at $(Get-CurrentLine). -String $String already has suffix of -Add $Add" - } - - return $ReturnValue -} -export-modulemember -function Add-Suffix - -#----------------------------------------------------------------------- -# Compare-IsFirst [-String []] -# -# Example: .\Compare-IsFirst -String Hell -EndsWith H -# Result: false -# Example: .\Compare-IsFirst -String Hello -Add H -# Result: Hello -#----------------------------------------------------------------------- -function Compare-IsFirst -{ - param ( - [Parameter(Mandatory=$true,ValueFromPipelineByPropertyName=$true)] - [string]$String = $(throw '-String is a required parameter.'), - [Parameter(Mandatory=$true,ValueFromPipelineByPropertyName=$true)] - [string]$BeginsWith = $(throw '-BeginsWith is a required parameter.') - ) - - Write-Verbose "Compare-IsFirst -String $String -EndsWith $EndsWith" - [Boolean]$ReturnValue = $false - if($BeginsWith.Length -lt $String.Length) - { - $StringBeginning = $String.SubString(0, $BeginsWith.Length).ToLower() - if ($StringBeginning.ToLower().Equals($BeginsWith.ToLower())) - { - $ReturnValue = $true - } - Write-Verbose "[Success] 1 items affected. $(Get-CurrentFile) at $(Get-CurrentLine)." - } - else - { - Write-Verbose "[OK] 0 items affected. $(Get-CurrentFile) at $(Get-CurrentLine)." - } - return $ReturnValue -} -export-modulemember -function Compare-IsFirst - -#----------------------------------------------------------------------- -# Compare-IsLast [-String []] -# -# Example: .\Compare-IsLast -String Hell -EndsWith H -# Result: false -# Example: .\Compare-IsLast -String Hello -Add H -# Result: Hello -#----------------------------------------------------------------------- -function Compare-IsLast -{ - param ( - [Parameter(Mandatory=$true,ValueFromPipelineByPropertyName=$true)] - [string]$String = $(throw '-String is a required parameter.'), - [Parameter(Mandatory=$true,ValueFromPipelineByPropertyName=$true)] - [string]$EndsWith = $(throw '-EndsWith is a required parameter.') - ) - Write-Verbose "Compare-IsLast -String $String -EndsWith $EndsWith" - [Boolean]$ReturnValue = $false - if($EndsWith.Length -lt $String.Length) - { - $StringEnding = $String.SubString(($String.Length - $EndsWith.Length), $EndsWith.Length) - if ($StringEnding.ToLower().Equals($EndsWith.ToLower())) - { - $ReturnValue = $true - } - Write-Verbose "[Success] 1 items affected. $(Get-CurrentFile) at $(Get-CurrentLine)." - } - else - { - Write-Verbose "[OK] 0 items affected. $(Get-CurrentFile) at $(Get-CurrentLine)." - } - - return $ReturnValue -} -export-modulemember -function Compare-IsLast - -#----------------------------------------------------------------------- -# Compress-Path [-Path []] [-File []] -# -# Example: .\Compress-Path \\source\path \\destination\path\file.zip -#----------------------------------------------------------------------- -function Compress-Path -{ - param ( - [Parameter(Mandatory=$true,ValueFromPipelineByPropertyName=$true)] - [string]$Path=$(throw '-Path is a required parameter.'), - [Parameter(Mandatory=$true,ValueFromPipelineByPropertyName=$true)] - [string]$File=$(throw '-File is a required parameter.') - ) - Write-Verbose "Compress-Path -Path $Path -File $File" - New-Path -Path $Path - Remove-File $File - [Reflection.Assembly]::LoadWithPartialName("System.IO.Compression.FileSystem") - [System.IO.Compression.ZipFile]::CreateFromDirectory($Path, $File) -} -export-modulemember -function Compress-Path - -#----------------------------------------------------------------------- -# Convert-PathSafe [-Path []] -# -# Example: .\Convert-PathSafe -Path \\source\path -#----------------------------------------------------------------------- -function Convert-PathSafe -{ - param ( - [Parameter(Mandatory=$true,ValueFromPipelineByPropertyName=$true)] - [string]$Path = $(throw '-Path is a required parameter.') - ) - Write-Verbose "Convert-PathSafe -Path $Path" - $Path = $Path.Trim() - $ReturnValue = $Path - $Path = Set-Unc -Path $Path - if(Test-Path -Path $Path) - { - $ReturnValue = Convert-Path -Path $Path - if (-not ($ReturnValue)) - { - $ReturnValue = $Path - Write-Verbose "[Warning] 0 items affected. $(Get-CurrentFile) at $(Get-CurrentLine). $(Get-CurrentFile) at $(Get-CurrentLine). -Path $Path didnt convert." - } - } - else - { - Write-Verbose "[Error] 0 items affected. $(Get-CurrentFile) at $(Get-CurrentLine). $(Get-CurrentFile) at $(Get-CurrentLine). -Path $Path does not exist." - } - return $ReturnValue -} -export-modulemember -function Convert-PathSafe - -#----------------------------------------------------------------------- -# Copy-Backup [-Path []] [-Destination []] -# -# Example: .\Copy-Backup -Path \\source\path -Destination \\destination\path -#----------------------------------------------------------------------- -function Copy-Backup -{ - param ( - [Parameter(Mandatory=$true,ValueFromPipelineByPropertyName=$true)] - [string]$Path = $(throw '-Path is a required parameter.'), - [Parameter(Mandatory=$true,ValueFromPipelineByPropertyName=$true)] - [string]$Destination = $(throw '-Destination is a required parameter.') - ) - Write-Verbose "Copy-Backup -Path $Path -Destination $Destination" - $Path = Remove-Suffix -String $Path -Remove "\" - New-Path -Path $Destination - [String]$BackupPath=[string]::Format("{0}\{1}", $Destination, (Get-Date).ToString("yyyy-MM-dd")) - if($Path) - { - if(-not (Test-Path -Path $BackupPath -PathType Container)){ - New-Path -Path $BackupPath - } - Copy-Recurse -Path $Path -Destination $BackupPath - Write-Verbose "[Success] 1 items affected. $(Get-CurrentFile) at $(Get-CurrentLine). -Path $Path to -Destination $BackupPath" - } - else - { - Write-Verbose "[Error] 0 items affected. $(Get-CurrentFile) at $(Get-CurrentLine). $(Get-CurrentFile) at $(Get-CurrentLine). -Path $Path does not exist." - } -} -export-modulemember -function Copy-Backup - -#----------------------------------------------------------------------- -# Copy-File [-Path []] [-Destination []] -# -# Example: .\Copy-File -Path \\source\path\File.name -Destination \\destination\path -#----------------------------------------------------------------------- -function Copy-File -{ - param ( - [Parameter(Mandatory = $True)] - [string]$Path = $(throw '-Path is a required parameter.'), - [Parameter(Mandatory = $True)] - [string]$Destination = $(throw '-Destination is a required parameter.'), - [string[]]$Include = "*.*", - [string[]]$Exclude = "", - [bool]$Overwrite = $true - ) - Write-Verbose "Copy-File -Path $Path -Destination $Destination -Overwrite $Overwrite" - $Destination = Set-Unc -Path $Destination - if(Test-File -Path $Path) - { - New-Path -Path $Destination - $DestinationAbsolute = $Destination - if(Test-Folder -Path $Destination) - { - $DestinationAbsolute = Convert-PathSafe -Path $Destination - } - $DestinationPathFile = $DestinationAbsolute - $FolderArray = $Path.Split('\') - if($FolderArray.Count -gt 0) - { - $DestinationPathFile = Join-Path $DestinationAbsolute $FolderArray[$FolderArray.Count-1] - } - if((-not (Test-Path $DestinationPathFile -PathType Leaf)) -or ($Overwrite -eq $true)) - { - try{ - Copy-Item -Path $Path -Destination $DestinationAbsolute -Include $Include -Exclude $Exclude -Force - } - catch{ - Write-Verbose "[Error] 0 items affected. $(Get-CurrentFile) at $(Get-CurrentLine). -Path $Path does not exist." - } - } - Write-Verbose "[Success] 1 items affected. $(Get-CurrentFile) at $(Get-CurrentLine). -Path $Path to -Destination $DestinationAbsolute" - } - else - { - Write-Verbose "[Error] 0 items affected. $(Get-CurrentFile) at $(Get-CurrentLine). -Path $Path does not exist." - } -} -export-modulemember -function Copy-File - -#----------------------------------------------------------------------- -# Copy-Recurse [-Source []] [-Destination []] -# [-Include [] [-Exclude []] -# -# Example: .\Copy-Recurse \\source\path \\destination\path -#----------------------------------------------------------------------- -function Copy-Recurse -{ - param ( - [Parameter(Mandatory=$true,ValueFromPipelineByPropertyName=$true)] - [string]$Path = $(throw '-Source is a required parameter.'), - [Parameter(Mandatory=$true,ValueFromPipelineByPropertyName=$true)] - [string]$Destination = $(throw '-Destination is a required parameter.'), - [string[]]$Include = "*.*", - [string[]]$Exclude = "", - [Int32]$First = 1000, - [bool]$Overwrite=$True, - [bool]$Clean = $False - ) - Write-Verbose "Copy-Recurse -Path $Path -Destination $Destination -Include $Include -Exclude $Exclude -First $ -Overwrite $Overwrite -Clean $Clean" - $Affected = 0 - $Path = Set-Unc -Path $Path - if (Test-Path $Path) - { - $PathAbsolute = Convert-PathSafe -Path $Path - # Optionally Clean - if($Clean -eq $True) { Remove-Path -Path $Destination } - New-Path -Path $Destination - $DestinationAbsolute = $Destination - if(Test-Path $Destination) { $DestinationAbsolute=Convert-PathSafe -Path $Destination } - $Items = Get-ChildItem -Path $PathAbsolute -Recurse -Include $Include -Exclude $Exclude | where { ! $_.PSIsContainer } - ForEach ($Item in $Items) { - $PathArray = $PathAbsolute.Split('\') - $Folder = $DestinationAbsolute - for ($count=1; $count -lt $PathArray.length-1; $count++) { - $Subfolder = $PathArray[$count] - $Folder = Join-Path $Folder $Subfolder - if (($Folder.Length > 0) -and (-not (Test-Path $Folder))) { - Write-Verbose "New-Item -ItemType directory -Force -Path $Folder" - New-Item -ItemType directory -Force -Path $Folder - } - } - $DirName = $Item.DirectoryName - $Position = $DirName.IndexOf($PathAbsolute) - $PathSegment = $DirName.SubString($Position + $PathAbsolute.Length) - $NewPath = Join-Path $DestinationAbsolute $PathSegment - Copy-File -Path $Item.FullName -Destination $NewPath -Overwrite $Overwrite - $Affected = $Affected + 1 - } - Write-Verbose "[Success] $Affected items affected. $(Get-CurrentFile) at $(Get-CurrentLine)." - } - else - { - Write-Verbose "[Error] 0 items affected. $(Get-CurrentFile) at $(Get-CurrentLine). -Path $Path does not exist." - } -} -export-modulemember -function Copy-Recurse - -#----------------------------------------------------------------------- -# Expand-File [-Path []] [-File []] -# -# Example: .\Expand-File \\source\path\file.zip \\destination\path -#----------------------------------------------------------------------- -function Expand-File -{ - param ( - [Parameter(Mandatory=$true,ValueFromPipelineByPropertyName=$true)] - [string]$Path=$(throw '-Path is a required parameter.'), - [Parameter(Mandatory=$true,ValueFromPipelineByPropertyName=$true)] - [string]$File=$(throw '-File is a required parameter.') - ) - Write-Verbose "Expand-Zip -Path $Path -File $File" - New-Path -Path $Path - [Reflection.Assembly]::LoadWithPartialName("System.IO.Compression.FileSystem") - [System.IO.Compression.ZipFile]::ExtractToDirectory($File, $Path) -} -export-modulemember -function Expand-File - -#----------------------------------------------------------------------- -# Find-File [-Path []] [-File []] -# -# Example: .\Find-File \\source\path\file.zip \\destination\path -#----------------------------------------------------------------------- -function Find-File -{ - param ( - [Parameter(Mandatory=$true,ValueFromPipelineByPropertyName=$true)] - [string]$Path=$(throw '-Path is a required parameter.'), - [Parameter(Mandatory=$true,ValueFromPipelineByPropertyName=$true)] - [string]$File=$(throw '-File is a required parameter.'), - [Int32]$First=1 - ) - Write-Verbose "Find-Zip -Path $Path -File $File" - Get-Childitem -Path $Path -Include $File -Recurse| select -First $First -} -export-modulemember -function Find-File - -#----------------------------------------------------------------------- -# Get-AssemblyStrongName -# -# Example: Get-AssemblyStrongName -#----------------------------------------------------------------------- -function Get-AssemblyStrongName($assemblyPath) -{ - [System.Reflection.AssemblyName]::GetAssemblyName($assemblyPath).FullName -} -export-modulemember -function Get-AssemblyStrongName - -#----------------------------------------------------------------------- -# Get-CurrentLine -# -# Example: Get-CurrentLine -#----------------------------------------------------------------------- -function Get-CurrentLine { - $MyInvocation.ScriptLineNumber -} -export-modulemember -function Get-CurrentLine - -#----------------------------------------------------------------------- -# Get-CurrentFile -# -# Example: Get-CurrentFile -#----------------------------------------------------------------------- -function Get-CurrentFile { - $MyInvocation.ScriptName -} -export-modulemember -function Get-CurrentFile - -#----------------------------------------------------------------------- -# Get-FilesByString -# -# Example: Get-FilesByString -#----------------------------------------------------------------------- -function Get-FilesByString { - param ( - [Parameter(Mandatory=$true,ValueFromPipelineByPropertyName=$true)] - [string]$Path = $(throw '-Path is a required parameter.'), - [string]$String = $(throw '-String is a required parameter.'), - [string[]]$Include = ("*.*"), - [string[]]$Exclude = "" - ) - Write-Verbose "Get-FilesByString -Path $Path -String $String -Include $Include -Exclude $Exclude" - $Path = Set-Unc -Path $Path - - $ReturnData = Get-Childitem -Path $Path -Include $Include -Exclude $Exclude -Recurse | Select-String -pattern $String | group path | select name - - return $ReturnData -} -export-modulemember -function Get-FilesByString - -#----------------------------------------------------------------------- -# Get-SystemFolders -# -# Example: Get-SystemFolder -#----------------------------------------------------------------------- -function Get-SystemFolders -{ - param ( - ) - Write-Verbose "Get-SystemFolders" - $SpecialFolders = @{} - $names = [Environment+SpecialFolder]::GetNames([Environment+SpecialFolder]) - foreach($name in $names) - { - if($path = [Environment]::GetFolderPath($name)){ - $SpecialFolders[$name] = $path - } - else - { - Write-Verbose "[Warning] 0 items affected. $(Get-CurrentFile) at $(Get-CurrentLine)." - } - } - return $SpecialFolders -} -export-modulemember -function Get-SystemFolders - -#----------------------------------------------------------------------- -# Get-SystemFolder [-Name []] -# Keys: Desktop,Programs,MyDocuments,Personal,Favorites,Startup,Recent,SendTo,StartMenu,MyMusic,MyVideos,DesktopDirectory,NetworkShortcuts,Fonts -# Templates,CommonStartMenu,CommonPrograms,CommonStartup,CommonDesktopDirectory,ApplicationData,PrinterShortcuts,LocalApplicationData,InternetCache -# Cookies,History,CommonApplicationData,Windows,System,ProgramFiles,MyPictures,UserProfile,SystemX86,ProgramFilesX86 -# CommonProgramFiles,CommonProgramFilesX86,CommonTemplates,CommonDocuments,CommonAdminTools,AdminTools,CommonMusic,CommonPictures,CommonVideos,ResourcesCDBurning -# Example: Get-SystemFolder -Name 'UserProfile' -#----------------------------------------------------------------------- -function Get-SystemFolder -{ - param ( - [Parameter(Mandatory=$true,ValueFromPipelineByPropertyName=$true)] - [String]$Name=$(throw '-Folder is a required parameter.') - ) - Write-Verbose "Get-SystemFolder -Folder $Folder" - if($path = [Environment]::GetFolderPath($name)){ - $Folder = $path - } - else - { - Write-Verbose "[Warning] 0 items affected. $(Get-CurrentFile) at $(Get-CurrentLine)." - } - return $Folder -} -export-modulemember -function Get-SystemFolder - -#----------------------------------------------------------------------- -# Move-Path [-Path []] [-Destination []] -# [-Exclude []] -# -# Example: .\Move-Path -Path \\source\path -#----------------------------------------------------------------------- -function Move-Path -{ - param ( - [Parameter(Mandatory=$true,ValueFromPipelineByPropertyName=$true)] - [string]$Path = $(throw '-Path is a required parameter.'), - [Parameter(Mandatory=$true,ValueFromPipelineByPropertyName=$true)] - [string]$Destination = $(throw '-Destination is a required parameter.'), - [string]$Exclude = "" - ) - Write-Verbose "Move-Path -Path $Path -Destination $Destination" - $Path = Remove-Suffix -String $Path -Remove "\" - if (test-folder -Path $Path) - { - Remove-Path -Destination $Destination - New-Path -Destination $Destination - Copy-Recurse -Path $Path -Destination $Destination -Exclude $Exclude - Remove-Path -Destination $Path - Write-Verbose "[Success] 1 items affected. $(Get-CurrentFile) at $(Get-CurrentLine). -Path $Path moved to -Destination $Destination" - } - else - { - Write-Verbose "[Error] 0 items affected. $(Get-CurrentFile) at $(Get-CurrentLine). -Path $Path does not exist." - } -} -export-modulemember -function Move-Path - -#----------------------------------------------------------------------- -# New-Path [-Path []] -# -# Example: .\New-Path \\source\path -#----------------------------------------------------------------------- -function New-Path -{ - param ( - [Parameter(Mandatory=$true,ValueFromPipelineByPropertyName=$true)] - [string]$Path = $(throw '-Path is a required parameter.'), - [bool]$Clean=$false - ) - Write-Verbose "New-Path -Path $Path" - [String]$Folder = "" - $Path = Remove-Suffix -String $Path -Remove "\" - if ($Clean) {Remove-Path -Path $Path} - if (-not (test-path $Path)) { - if (Test-Unc $Path) - { - $PathArray = $Path.Split('\') - foreach($item in $PathArray) - { - if($item.Length -gt 0) - { - if($Folder.Length -lt 1) - { - $Folder = "\\$item" - } - else - { - $Folder = "$Folder\$item" - if (-not (Test-Path $Folder)) { - New-Item -ItemType directory -Path $Folder -Force - } - } - } - } - } - else - { - New-Item -ItemType directory -Path $Path -Force - } - } -} -export-modulemember -function New-Path - -#----------------------------------------------------------------------- -# Redo-Path [-Path []] [-Destination []] -# [-Exclude []] -# -# Example: .\Redo-Path -Path \\source\path -#----------------------------------------------------------------------- -function Redo-Path -{ - param ( - [Parameter(Mandatory=$true,ValueFromPipelineByPropertyName=$true)] - [string]$Path = $(throw '-Path is a required parameter.'), - [Parameter(Mandatory=$true,ValueFromPipelineByPropertyName=$true)] - [string]$Destination = $(throw '-Destination is a required parameter.'), - [string]$Exclude = "" - ) - Write-Verbose "Redo-Path -Path $Path -Destination $Destination" - $Path = Remove-Suffix -String $Path -Remove "\" - Remove-Path -Destination $Path - New-Path -Destination $Path - Copy-Recurse -Path $Path -Destination $Destination -Exclude $Exclude - Write-Verbose "[Success] 1 items affected. $(Get-CurrentFile) at $(Get-CurrentLine). -Path $Path to -Destination $Destination" -} -export-modulemember -function Redo-Path - -#----------------------------------------------------------------------- -# Remove-File [-File []] -# -# Example: .\Remove-File \\source\path\file.txt -#----------------------------------------------------------------------- -function Remove-File -{ - param ( - [Parameter(Mandatory=$true,ValueFromPipelineByPropertyName=$true)] - [string]$Path=$(throw '-Path is a required parameter.') - ) - Write-Verbose "Remove-File -Path $Path" - if (Test-File -Path $Path) { - Remove-Item -Path $Path -Force - Write-Verbose "[Success] 1 items affected. $(Get-CurrentFile) at $(Get-CurrentLine). -Path $Path removed." - } - else - { - Write-Verbose "[Error] 0 items affected. $(Get-CurrentFile) at $(Get-CurrentLine). -Path $Path does not exist." - } -} -export-modulemember -function Remove-File - -#----------------------------------------------------------------------- -# Remove-Path [-Path []] -# [-Include [] [-Exclude []] -# -# Example: .\Remove-Path -Path \\source\path -#----------------------------------------------------------------------- -function Remove-Path -{ - param ( - [Parameter(Mandatory=$true,ValueFromPipelineByPropertyName=$true)] - [string]$Path = $(throw '-Path is a required parameter.'), - [string[]]$Include = "*.*", - [string[]]$Exclude = "", - [Int16]$Retention = 1, - [Int32]$First = 1000 - ) - Write-Verbose "Remove-Path -Path $Path -Include $Include -Exclude $Exclude -Retention $Retention -First $First" - $Path = Remove-Suffix -String $Path -Remove "\" - if (test-folder -Path $Path) { - $ErrorActionPreferenceBackup = $ErrorActionPreference - $ErrorActionPreference = 'SilentlyContinue' - Get-ChildItem -Path $Path -Include $Include -Exclude $Exclude -Recurse | Where-Object {($_.PSIsContainer) -and ($_.lastwritetime -le (get-date).addDays(($Retention*-1)))} | select -First $First | Remove-Item -Force -Recurse - Remove-Item $Path -Recurse -Force - $ErrorActionPreference = $ErrorActionPreferenceBackup - Write-Verbose "[Success] 1 items affected. $(Get-CurrentFile) at $(Get-CurrentLine). -Path $Path removed." - } - else - { - Write-Verbose "[Warning] 0 items affected. $(Get-CurrentFile) at $(Get-CurrentLine)." - } -} -export-modulemember -function Remove-Path - -#----------------------------------------------------------------------- -# Remove-Subfolders [-Path []] -# [-Include [] [-Exclude []] -# -# Example: .\Remove-Subfolders -Path \\source\path -#----------------------------------------------------------------------- -function Remove-Subfolders -{ - param ( - [Parameter(Mandatory=$true,ValueFromPipelineByPropertyName=$true)] - [string]$Path = $(throw '-Path is a required parameter.'), - [Parameter(Mandatory=$true,ValueFromPipelineByPropertyName=$true)] - [string]$Subfolder = $(throw '-Subfolder is a required parameter.'), - [Int32]$First = 1000 - ) - Write-Verbose "Remove-Subfolders -Path $Path -Subfolder $Subfolder -First $First" - $Path = Set-Unc -Path $Path - - if (test-folder -Path $Path) { - $Affected = 0 - if(Test-Unc -Path $Path) - { - $Folders=Get-ChildItem $Path -Recurse | Where-Object {($_.Name -EQ $Subfolder) -and ($_.PSIsContainer)} | select -First $First - foreach ($Folder in $Folders) { - if ($Folder.FullName) - { - [String]$FolderToRemove=Add-Suffix -String $Folder.FullName -Add "\" - Remove-Path -Path $FolderToRemove - $Affected = $Affected + 1 - } - } - } - else - { - $Remove = Add-Suffix -String $Path -Add '\' - $Remove = Add-Suffix -String $Remove -Add $Subfolder - Remove-Path -Path $Remove - $Affected = 1 - } - Write-Verbose "[Success] $Affected items affected. $(Get-CurrentFile) at $(Get-CurrentLine). -Path $Path -Subfolder $Subfolder removed." - } - else - { - Write-Verbose "[Warning] 0 items affected. $(Get-CurrentFile) at $(Get-CurrentLine). -Path $Path does not exist." - } -} -export-modulemember -function Remove-Subfolders - -#----------------------------------------------------------------------- -# Remove-Recurse [-Source []] [-Destination []] -# [-Include [] [-Exclude []] -# -# Example: .\Remove-Recurse \\source\path \\destination\path -#----------------------------------------------------------------------- -function Remove-Recurse -{ - param ( - [Parameter(Mandatory=$true,ValueFromPipelineByPropertyName=$true)] - [string]$Path = $(throw '-Source is a required parameter.'), - [string[]]$Include = "*.*", - [string[]]$Exclude = "", - [Int32]$First = 1000 - ) - Write-Verbose "Remove-Recurse -Path $Path -Include $Include -Exclude $Exclude" - $Path = Remove-Suffix -String $Path -Remove "\" - if (Test-Path $Path) - { - $PathAbsolute = Convert-PathSafe -Path $Path - $Items = Get-ChildItem -Path $PathAbsolute -Recurse -Include $Include -Exclude $Exclude | where { ! $_.PSIsContainer } - $Affected = 0 - ForEach ($Item in $Items) { - Remove-File -Path $Item - $Affected = $Affected + 1 - } - Write-Verbose "[Success] $Affected items affected. $(Get-CurrentFile) at $(Get-CurrentLine). -Path $Path." - } - else - { - Write-Verbose "[Warning] 0 items affected. $(Get-CurrentFile) at $(Get-CurrentLine). -Path $Path does not exist." - } -} -export-modulemember -function Remove-Recurse - -#----------------------------------------------------------------------- -# Remove-Prefix [-String []] -# -# Example: .\Remove-Prefix -String Hell -Remove o -# Result: Hello -#----------------------------------------------------------------------- -function Remove-Prefix -{ - param ( - [Parameter(Mandatory=$true,ValueFromPipelineByPropertyName=$true)] - [string]$String = $(throw '-String is a required parameter.'), - [Parameter(Mandatory=$true,ValueFromPipelineByPropertyName=$true)] - [string]$Remove = $(throw '-Remove is a required parameter.') - ) - Write-Verbose "Remove-Prefix -String $String -Remove $Remove" - [string]$ReturnValue = $String - if (Compare-IsFirst -String $String -BeginsWith $Remove) - { - $ReturnValue = $String.Substring($Remove.Length, $String.Length - $Remove.Length) - Write-Verbose "[Success] 1 items affected. $(Get-CurrentFile) at $(Get-CurrentLine)." - } - else - { - Write-Verbose "[OK] 0 items affected. $(Get-CurrentFile) at $(Get-CurrentLine). -String $String already has prefix of -Remove $Remove" - } - - return $ReturnValue -} -export-modulemember -function Remove-Prefix - -#----------------------------------------------------------------------- -# Remove-Suffix [-String []] -# -# Example: .\Remove-Suffix -String Hell -Remove o -# Result: Hello -#----------------------------------------------------------------------- -function Remove-Suffix -{ - param ( - [Parameter(Mandatory=$true,ValueFromPipelineByPropertyName=$true)] - [string]$String = $(throw '-String is a required parameter.'), - [Parameter(Mandatory=$true,ValueFromPipelineByPropertyName=$true)] - [string]$Remove = $(throw '-Remove is a required parameter.') - ) - Write-Verbose "Remove-Suffix -String $String -Remove $Remove" - [string]$ReturnValue = $String - if($String) - { - if (Compare-IsLast -String $String -EndsWith $Remove) - { - $ReturnValue = $ReturnValue.Substring(0, $String.Length - $Remove.Length) - } - Write-Verbose "[Success] 1 items affected. $(Get-CurrentFile) at $(Get-CurrentLine)." - } - else - { - Write-Verbose "[OK] 0 items affected. $(Get-CurrentFile) at $(Get-CurrentLine). -String $String already has suffix of -Remove $Remove" - } - - return $ReturnValue -} -export-modulemember -function Remove-Suffix - -#----------------------------------------------------------------------- -# Remove-Element [-Path []] -# -# Example: .\Remove-Element -Value "" -# -XPath "//msb:None/msb:Generator" -# -Namespace @{msb = "http://schemas.microsoft.com/developer/msbuild/2003"} -# -# Called: $XMLValue = [xml](Get-Content $path) -# $Namespace = @{msb = 'http://schemas.microsoft.com/developer/msbuild/2003'} -# Remove-Element $XMLValue -XPath '//msb:None/msb:Generator' -Namespace $Namespace -# $proj.Save($path) -#----------------------------------------------------------------------- -function Remove-Element -{ - param ( - [Parameter(Mandatory=$true,ValueFromPipelineByPropertyName=$true)] - [xml]$Value=$(throw '-Value is a required parameter.'), - [Parameter(Mandatory=$true,ValueFromPipelineByPropertyName=$true)] - [String]$XPath=$(throw '-Value is a required parameter.'), - [Parameter(Mandatory=$true,ValueFromPipelineByPropertyName=$true)] - [String]$Namespace=$(throw '-Value is a required parameter.') - ) - Write-Verbose ".\Remove-Element -Value $Value -XPath $XPath -Namespace $Namespace -SingleNode" - $nodes = @(Select-Xml $XPath $Value -Namespace $Namespace | Foreach {$_.Node}) - if (!$nodes) { Write-Verbose "RemoveElement: XPath $XPath not found" } - if ($singleNode -and ($nodes.Count -gt 1)) { - throw "XPath $XPath found multiple nodes" - } - $Count = 0 - foreach ($node in $nodes) - { - $parentNode = $node.ParentNode - [void]$parentNode.RemoveChild($node) - $Count = $Count + 1 - } - Write-Verbose "[Success] $Count items affected. $(Get-CurrentFile) at $(Get-CurrentLine)." -} -export-modulemember -function Remove-Element - -#----------------------------------------------------------------------- -# Remove-ContentsByTagContains [-Path []] -# [-Open [] [-Close []] -# -# Example: .\Remove-ContentsByTagContains \\source\path \\destination\path -# GlobalSection(TeamFoundationVersionControl) = preSolution -# EndGlobalSection -#----------------------------------------------------------------------- -function Remove-ContentsByTag -{ - param ( - [Parameter(Mandatory=$true,ValueFromPipelineByPropertyName=$true)] - [string]$Path = $(throw '-Path is a required parameter.'), - [Parameter(Mandatory=$true,ValueFromPipelineByPropertyName=$true)] - [string]$Open = $(throw '-Open is a required parameter.'), - [Parameter(Mandatory=$true,ValueFromPipelineByPropertyName=$true)] - [string]$Close = $(throw '-Close is a required parameter.'), - [string[]]$Include = "*.*", - [string[]]$Exclude = "", - [Int32]$First = 100 - ) - Write-Verbose "Remove-ContentsByTag -Path $Path -Open $Open -Close $Close -Include $Include -Exclude $Exclude -First $First" - $Path = Remove-Suffix -String $Path -Remove "\" - if (Test-Path $Path) - { - $Open = $Open.Trim() - $Close = $Close.Trim() - $Files = Get-Childitem -Path $Path -Include $Include -Exclude $Exclude -Recurse -Force | select -First $First - ForEach ($File in $Files) - { - [Int32]$OpenIndex = -1 - [Int32]$CloseIndex = -1 - $Content=Get-Content $File.PSPath - # Search for matches - For([Int32]$Count = 0; $Count -lt $Content.Length; $Count++) - { - $CurrentLine = $Content[$Count].Trim() - If(($OpenIndex -eq -1) -and ($CurrentLine -eq $Open)) - { - $OpenIndex = $Count - } - ElseIf(($OpenIndex -gt -1) -and ($CurrentLine -eq $Close)) - { - $CloseIndex = $Count - Break - } - } - # Evaluate search - If(($OpenIndex -gt -1) -and ($OpenIndex -lt $CloseIndex)) - { - # Match Found Remove block. - $NewContent = ($Content | Select -First $OpenIndex) + ($Content | select -Last ($Content.Length - $CloseIndex - 1)) - } - else - { - # No Match Found - $NewContent = $Content - } - Set-Content $File.PSPath -Value $NewContent - } - Write-Verbose "[Success] 1 items affected. $(Get-CurrentFile) at $(Get-CurrentLine)." - } - else - { - Write-Verbose "[OK] 0 items affected. $(Get-CurrentFile) at $(Get-CurrentLine)." - } -} -export-modulemember -function Remove-ContentsByTag - -#----------------------------------------------------------------------- -# Remove-ContentsByTagContains [-Path []] -# [-Open [] [-Close []] -# -# Example: .\Remove-ContentsByTagContains \\source\path \\destination\path -# GlobalSection(TeamFoundationVersionControl) = preSolution -# EndGlobalSection -#----------------------------------------------------------------------- -function Remove-ContentsByTagContains -{ - param ( - [Parameter(Mandatory=$true,ValueFromPipelineByPropertyName=$true)] - [string]$Path = $(throw '-Path is a required parameter.'), - [Parameter(Mandatory=$true,ValueFromPipelineByPropertyName=$true)] - [string]$Open = $(throw '-Open is a required parameter.'), - [Parameter(Mandatory=$true,ValueFromPipelineByPropertyName=$true)] - [string]$Close = $(throw '-Close is a required parameter.'), - [Parameter(Mandatory=$true,ValueFromPipelineByPropertyName=$true)] - [string]$Contains = $(throw '-Contains is a required parameter.'), - [string[]]$Include = "*.*", - [string[]]$Exclude = "", - [Int32]$First = 100 - ) - Write-Verbose "Remove-ContentsByTagContains -Path $Path -Open $Open -Close $Close -Contains $Contains -Include $Include -Exclude $Exclude -First $First" - $Path = Remove-Suffix -String $Path -Remove "\" - if (Test-Path $Path) - { - $Open = $Open.Trim() - $Close = $Close.Trim() - $Contains = $Contains.Trim() - - $Files = Get-Childitem -Path $Path -Include $Include -Exclude $Exclude -Recurse -Force | select -First $First - ForEach ($File in $Files) - { - [Int32]$OpenIndex = -1 - [Int32]$ContainsIndex = -1 - [Int32]$CloseIndex = -1 - $Content=Get-Content $File.PSPath - # Search for matches - For([Int32]$Count = 0; $Count -lt $Content.Length; $Count++) - { - $CurrentLine = $Content[$Count].Trim() - If ($CurrentLine -like "*$Open*") - { - If($OpenIndex -gt -1) - { - # Fail: Block did not contain -Content and/or -Open was found before -Close. Reset for next open tag match. - $ContainsIndex = -1 - $CloseIndex = -1 - } - $OpenIndex = $Count - }ElseIf($OpenIndex -gt -1) - { - If($CurrentLine -like "*$Contains*") - { - $ContainsIndex = $Count - }ElseIf(($ContainsIndex -gt -1) -and ($CurrentLine -like "*$Close*")) - { - # Success, block starts with -Open, ends with -Close and includes -Contains - $CloseIndex = $Count - Break - } - } - } - # Any matches? - If(($OpenIndex -gt -1) -and ($ContainsIndex -gt $OpenIndex) -and ($CloseIndex -gt $ContainsIndex)) - { - If($CloseIndex -eq ($OpenIndex + 2)) - { - # Match Found with single element. Remove Block. - $NewContent = ($Content | Select -First $OpenIndex) + ($Content | select -Last ($Content.Length - $CloseIndex - 1)) - } - Else - { - # Match Found with multiple elements. Remove Line Only. - $NewContent = ($Content | Select -First $ContainsIndex) + ($Content | select -Last ($Content.Length - $ContainsIndex -1)) - } - } - else - { - # No Match Found - $NewContent = $Content - } - Set-Content $File.PSPath -Value $NewContent - } - Write-Verbose "[Success] 1 items affected. $(Get-CurrentFile) at $(Get-CurrentLine)." - } - else - { - Write-Verbose "[OK] 0 items affected. $(Get-CurrentFile) at $(Get-CurrentLine)." - } -} -export-modulemember -function Remove-ContentsByTagContains - -#----------------------------------------------------------------------- -# Rename-File [-File []] -# -# Example: .\Rename-File -Path ($StagingZipPath + 'root.vstbak') -NewName root.vstemplate -Force -#----------------------------------------------------------------------- -function Rename-File -{ - param ( - [Parameter(Mandatory=$true,ValueFromPipelineByPropertyName=$true)] - [string]$Path=$(throw '-Path is a required parameter.'), - [string]$NewName=$(throw '-NewName is a required parameter.') - ) - Write-Verbose "Rename-File -Path $Path -NewName $NewName" - if (Test-File -Path $Path) { - Rename-Item -Path $Path -NewName $NewName -Force - Write-Verbose "[Success] 1 items affected. $(Get-CurrentFile) at $(Get-CurrentLine). -Path $Path removed." - } - else - { - Write-Verbose "[Error] 0 items affected. $(Get-CurrentFile) at $(Get-CurrentLine). -Path $Path does not exist." - } -} -export-modulemember -function Rename-File - -#----------------------------------------------------------------------- -# Set-ReadOnly [-Path []] [-ReadOnly []] -# -# Example: .\Set-ReadOnly -Path \\source\path\File.name -ReadOnly $False -#----------------------------------------------------------------------- -function Set-ReadOnly -{ - param ( - [Parameter(Mandatory = $True)] - [string]$Path = $(throw '-Path is a required parameter.'), - [bool]$ReadOnly = $True, - [string]$ErrorPreference = 'SilentlyContinue' - ) - Write-Verbose "Set-ReadOnly -Path $Path -ReadOnly $ReadOnly -ErrorPreference $ErrorPreference" - $Path = Remove-Suffix -String $Path -Remove "\" - if(test-path $Path) - { - $PathAbsolute = Convert-PathSafe -Path $Path - if (Test-Path $PathAbsolute -PathType Leaf) - { - $ErrorActionPreferenceBackup = $ErrorActionPreference - $ErrorActionPreference = $ErrorPreference - Set-ItemProperty $PathAbsolute -name IsReadOnly -value $ReadOnly -Force - $ErrorActionPreference = $ErrorActionPreferenceBackup - } - Write-Verbose "[Success] 1 items affected. $(Get-CurrentFile) at $(Get-CurrentLine). -Path $Path set." - } - else - { - Write-Verbose "[Error] 0 items affected. $(Get-CurrentFile) at $(Get-CurrentLine). -Path $Path does not exist." - } -} -export-modulemember -function Set-ReadOnly - -#----------------------------------------------------------------------- -# Set-SystemFolderDrives -# -# Example: Set-SystemFolderDrives -#----------------------------------------------------------------------- -function Set-SystemFolderDrives -{ - param ( - ) - Write-Verbose "Set-SystemFolderDrives" - - $SpecialFolders = @{} - $names = [Environment+SpecialFolder]::GetNames([Environment+SpecialFolder]) - foreach($name in $names) - { - if($path = [Environment]::GetFolderPath($name)){ - $SpecialFolders[$name] = $path - New-PSDrive -Name $name -PSProvider FileSystem -Root $path - } - } - # #TBD: Find the 10 Largest Files in the Documents Folder - # gci Personal: -Recurse -Force -ea SilentlyContinue | - # Sort-Object -Property Length -Descending | - # Select-Object -First 10 | - # Format-Table -AutoSize -Wrap -Property ` - # Length,LastWriteTime,FullName - return $SpecialFolders -} -export-modulemember -function Set-SystemFolderDrives - -#----------------------------------------------------------------------- -# Test-File [-Path []] -# -# Example: .\Test-File -Path \\source\path -#----------------------------------------------------------------------- -function Test-File -{ - param ( - [Parameter(Mandatory=$true,ValueFromPipelineByPropertyName=$true)] - [string]$Path = $(throw '-Path is a required parameter.') - ) - Write-Verbose "Test-File -Path $Path" - [bool]$ReturnValue = $false - if(Test-Path -Path $Path -PathType Leaf) - { - $ReturnValue = $true - } - else - { - Write-Verbose "[Warning] 0 items affected. $(Get-CurrentFile) at $(Get-CurrentLine). -Path $Path does not exist or is not a File." - } - return $ReturnValue -} -export-modulemember -function Test-File - -#----------------------------------------------------------------------- -# Test-Folder [-Path []] -# -# -# Example: .\Test-Folder -Path \\source\path -#----------------------------------------------------------------------- -function Test-Folder -{ - param ( - [Parameter(Mandatory=$true,ValueFromPipelineByPropertyName=$true)] - [string]$Path = $(throw '-Path is a required parameter.') - ) - Write-Verbose "Test-Folder -Path $Path" - [bool]$ReturnValue = $false - if(test-path -Path $Path -PathType Container) - { - $ReturnValue = $true - } - else - { - Write-Verbose "[Warning] 0 items affected. $(Get-CurrentFile) at $(Get-CurrentLine). -Path $Path does not exist or is not a Folder." - } - return $ReturnValue -} -export-modulemember -function Test-Folder - -#----------------------------------------------------------------------- -# Test-PathEmpty [-Path []] -# -# Example: .\Test-PathEmpty -Path \\source\path -#----------------------------------------------------------------------- -function Test-PathEmpty -{ - param ( - [Parameter(Mandatory=$true,ValueFromPipelineByPropertyName=$true)] - [string]$Path = $(throw '-Path is a required parameter.') - ) - Write-Verbose "Test-PathEmpty -Path $Path" - [bool]$ReturnValue = $false - if((Get-ChildItem $Path -force | Select-Object -First 1 | Measure-Object).Count -eq 0) - { - $ReturnValue = $true - } - else - { - Write-Verbose "[Error] 0 items affected. $(Get-CurrentFile) at $(Get-CurrentLine). -Path $Path does not exist." - } - return $ReturnValue -} -export-modulemember -function Test-PathEmpty - -#----------------------------------------------------------------------- -# Set-Unc [-Path []] -# -# Example: .\Set-Unc -Path \\source\path -#----------------------------------------------------------------------- -function Set-Unc -{ - param ( - [Parameter(Mandatory=$true,ValueFromPipelineByPropertyName=$true)] - [string]$Path = $(throw '-Path is a required parameter.') - ) - Write-Verbose "Set-Unc -Path $Path" - $Path = $Path.Trim() - $Path = Remove-Suffix -String $Path -Remove '\' - if(-not ($Path.Contains(':\') -or $Path.Contains('.\') -or (Compare-IsFirst -String $Path -BeginsWith '\'))) - { - $ReturnValue = Add-Prefix -String $Path -Add '\\' - } - else - { - $ReturnValue = $Path - Write-Verbose "[OK] 0 items affected. $(Get-CurrentFile) at $(Get-CurrentLine). -Path $Path already a UNC, drive letter, absolute or relative path." - } - return $ReturnValue -} -export-modulemember -function Set-Unc - -#----------------------------------------------------------------------- -# Test-Unc [-Path []] -# -# -# Example: .\Test-Unc -Path \\source\path -#----------------------------------------------------------------------- -function Test-Unc -{ - param ( - [Parameter(Mandatory=$true,ValueFromPipelineByPropertyName=$true)] - [string]$Path = $(throw '-Path is a required parameter.') - ) - Write-Verbose "Test-Unc -Path $Path" - [bool]$ReturnValue = $false - if(($Path.Contains('\\')) -and (-not ($Path.Contains(':\')))) - { - $ReturnValue = $true - } - else - { - Write-Verbose "[OK] 0 items affected. $(Get-CurrentFile) at $(Get-CurrentLine)." - } - return $ReturnValue -} -export-modulemember -function Test-Unc - -#----------------------------------------------------------------------- -# Update-LineByContains [-Path []] -# [-Contains [] [-Close []] -# -# Example: .\Update-LineByContains -Path \\source\path -Include AssemblyInfo.cs -Contains 'AssemblyVersion(' -Line '[assembly: AssemblyVersion("5.20.07")]' -#----------------------------------------------------------------------- -function Update-LineByContains -{ - param ( - [Parameter(Mandatory=$true,ValueFromPipelineByPropertyName=$true)] - [string]$Path = $(throw '-Path is a required parameter.'), - [Parameter(Mandatory=$true,ValueFromPipelineByPropertyName=$true)] - [string]$Contains = $(throw '-Contains is a required parameter.'), - [Parameter(Mandatory=$true,ValueFromPipelineByPropertyName=$true)] - [string]$Line = $(throw '-Line is a required parameter.'), - [string[]]$Include = "*.*", - [string[]]$Exclude = "", - [Int32]$First = 100 - ) - Write-Verbose "Update-LineByContains -Path $Path -Contains $Contains -Line $Line -Include $Include -Exclude $Exclude -First $First" - $Path = Remove-Suffix -String $Path -Remove "\" - if (Test-Path $Path) - { - $Contains = $Contains.Trim() - $Count = 0 - $Files = Get-Childitem -Path $Path -Include $Include -Exclude $Exclude -Recurse -Force | select -First $First - ForEach ($File in $Files) - { - [Int32]$ContainsIndex = -1 - $Affected = 0 - $Content=Get-Content $File.PSPath - # Search for matches - For([Int32]$Count = 0; $Count -lt $Content.Length; $Count++) - { - $CurrentLine = $Content[$Count].Trim() - If(($ContainsIndex -eq -1) -and ($CurrentLine -eq $Contains)) - { - $ContainsIndex = $Count - Break - } - } - # Evaluate search - If($ContainsIndex -gt -1) - { - # Select before line, add -Line, select after line - $NewContent = (($Content | Select -First $ContainsIndex) + ($Line + [Environment]::NewLine) + ($Content | select -Last ($Content.Length - $ContainsIndex -1))) - } - else - { - # No Match Found - $NewContent = $Content - } - Set-Content $File.PSPath -Value $NewContent - $Affected = $Count - } - Write-Verbose "[Success] $Count items affected. $(Get-CurrentFile) at $(Get-CurrentLine)." - } - else - { - Write-Verbose "[OK] 0 items affected. $(Get-CurrentFile) at $(Get-CurrentLine)." - } -} -export-modulemember -function Update-LineByContains - -#----------------------------------------------------------------------- -# Update-ContentsByTag [-Path []] -# [-Open [] [-Close []] -# -# Example: .\Update-ContentsByTag -Path $Path -Include *.sln -Open "GlobalSection(TeamFoundationVersionControl) = preSolution" -Close "EndGlobalSection" -#----------------------------------------------------------------------- -function Update-ContentsByTag -{ - param ( - [Parameter(Mandatory=$true,ValueFromPipelineByPropertyName=$true)] - [string]$Path = $(throw '-Path is a required parameter.'), - [Parameter(Mandatory=$true,ValueFromPipelineByPropertyName=$true)] - [string]$Open = $(throw '-Open is a required parameter.'), - [Parameter(Mandatory=$true,ValueFromPipelineByPropertyName=$true)] - [string]$Close = $(throw '-Close is a required parameter.'), - [Parameter(Mandatory=$true,ValueFromPipelineByPropertyName=$true)] - [string]$Value = $(throw '-Value is a required parameter.'), - [string[]]$Include = "*.*", - [string[]]$Exclude = "", - [Int32]$First = 100 - ) - Write-Verbose "Update-ContentsByTag -Path $Path -Open $Open -Close $Close -Include $Include -Exclude $Exclude -First $First" - $Path = Remove-Suffix -String $Path -Remove "\" - [String]$PaddingLeft = ' ' - if (Test-Path $Path) - { - $Open = $Open.Trim() - $Close = $Close.Trim() - $Affected = 0 - $Files = Get-Childitem -Path $Path -Include $Include -Exclude $Exclude -Recurse -Force | select -First $First - ForEach ($File in $Files) - { - [Int32]$OpenIndex = -1 - [Int32]$CloseIndex = -1 - [String]$NewValue = "" - $Content=Get-Content $File.PSPath - # Search for matches - For([Int32]$Count = 0; $Count -lt $Content.Length; $Count++) - { - $CurrentLine = $Content[$Count].Trim() - If(($OpenIndex -eq -1) -and ($CurrentLine -like "*$Open*")) - { - $OpenIndex = $Count - } - If(($OpenIndex -gt -1) -and ($CurrentLine -like "*$Close*")) - { - $CloseIndex = $Count - Break - } - } - # Evaluate search - If(($OpenIndex -gt -1) -and ($OpenIndex -le $CloseIndex)) - { - if($OpenIndex -eq $CloseIndex) - { - # Open/Close on same line, rebuild the line with new contents - $NewValue = ($Open + $Value + $Close) - } - else - { - $NewValue = $Value - } - # Update content - $NewContent = ($Content | Select -First ($OpenIndex)) + ($PaddingLeft + $NewValue) + ($Content | select -Last ($Content.Length - $CloseIndex - 1)) - $Affected = 1 - } - else - { - # No Match Found - $NewContent = $Content - } - Set-Content $File.PSPath -Value $NewContent - } - Write-Verbose "[Success] $Affected items affected. $(Get-CurrentFile) at $(Get-CurrentLine)." - } - else - { - Write-Verbose "[OK] 0 items affected. $(Get-CurrentFile) at $(Get-CurrentLine)." - } -} -export-modulemember -function Update-ContentsByTag - -#----------------------------------------------------------------------- -# Update-Text [-Path []] -# [-Include [] [-Exclude []] -# -# Example: .\Update-Text -Path \\source\path -Include *.cs -Old "Use gotos" -New "Point at people who use gotos" -#----------------------------------------------------------------------- -function Update-Text -{ - param ( - [Parameter(Mandatory=$true,ValueFromPipelineByPropertyName=$true)] - [string]$Path = $(throw '-Path is a required parameter.'), - [Parameter(Mandatory=$true,ValueFromPipelineByPropertyName=$true)] - [string]$Old = $(throw '-Old is a required parameter.'), - [Parameter(Mandatory=$true,ValueFromPipelineByPropertyName=$true)] - [string]$New = $(throw '-New is a required parameter.'), - [Parameter(Mandatory=$true,ValueFromPipelineByPropertyName=$true)] - [string[]]$Include = $(throw '-Include is a required parameter.'), - [string[]]$Exclude = "", - [Int32]$First = 100 - ) - Write-Verbose "Update-Text -Path $Path -Old $Old -New $New -Include $Include -Exclude $Exclude -First $First" - $Path = Remove-Suffix -String $Path -Remove "\" - $Count = 0 - if (Test-Path $Path) - { - $ConfigFiles=Get-Childitem $Path -Include $Include -Exclude $Exclude -Recurse -Force | select -First $First - foreach ($Item in $ConfigFiles) - { - Set-ReadOnly -Path $Item.PSPath -ReadOnly $false - (Get-Content $Item.PSPath) | - Foreach-Object {$_.Replace($Old, $New) - } | - Set-Content $Item.PSPath -force - $Count = $Count + 1 - } - Write-Verbose "[Success] $Count items affected. $(Get-CurrentFile) at $(Get-CurrentLine)." - } - else - { - Write-Verbose "[OK] 0 items affected. $(Get-CurrentFile) at $(Get-CurrentLine)." - } -} -export-modulemember -function Update-Text - -#----------------------------------------------------------------------- -# Update-TextByContains [-Path []] -# [-Contains [] [-Close []] -# -# Example: .\Update-TextByContains -Path \\source\path -Include AssemblyInfo.cs -Contains 'AssemblyVersion(' -Line '[assembly: AssemblyVersion("5.20.07")]' -#----------------------------------------------------------------------- -function Update-TextByContains -{ - param ( - [string]$Path = $(throw '-Path is a required parameter.'), - [string]$Contains = $(throw '-Contains is a required parameter.'), - [string]$Old = $(throw '-Old is a required parameter.'), - [string]$New = $(throw '-New is a required parameter.'), - [string[]]$Include = "*.*", - [string[]]$Exclude = "", - [Int32]$First = 100 - ) - Write-Verbose "Update-TextByContains -Path $Path -Contains $Contains -Old $Old -New $New -Include $Include -Exclude $Exclude -First $First" - $Path = Remove-Suffix -String $Path -Remove "\" - if (Test-Path $Path) - { - $Contains = $Contains.Trim() - $Count = 0 - $Files = Get-Childitem -Path $Path -Include $Include -Exclude $Exclude -Recurse -Force | select -First $First - ForEach ($File in $Files) - { - [Int32]$FoundIndex = -1 - [String]$FoundLine = '' - $Affected = 0 - $Content=Get-Content $File.PSPath - # Search for matches - For([Int32]$Count = 0; $Count -lt $Content.Length; $Count++) - { - $CurrentLine = $Content[$Count].Trim() - If(($FoundIndex -eq -1) -and ($CurrentLine.ToLowerInvariant().Contains($Contains.ToLowerInvariant()))) - { - $FoundIndex = $Count - $FoundLine = $CurrentLine - Break - } - } - # Evaluate search - If($FoundIndex -gt -1) - { - # Replace text inside of line - $NewLine = $FoundLine.Replace($Old, $New) - # Select before line, add $NewLine, select after line - $NewContent = (($Content | Select -First $FoundIndex) + ($NewLine + [Environment]::NewLine) + ($Content | select -Last ($Content.Length - $FoundIndex -1))) - } - else - { - # No Match Found - $NewContent = $Content - } - Set-Content $File.PSPath -Value $NewContent - $Affected = $Count - } - Write-Verbose "[Success] $Count items affected. $(Get-CurrentFile) at $(Get-CurrentLine)." - } - else - { - Write-Verbose "[OK] 0 items affected. $(Get-CurrentFile) at $(Get-CurrentLine)." - } -} -export-modulemember -function Update-TextByContains - -#----------------------------------------------------------------------- -# Update-TextByTable [-Path []] [-Replace []] -# [-Include [] [-Exclude []] -# -# Example: .\Update-TextByTable -Path \\source\path -Include *.cs -# -Replace @{'Old1' = 'New1' -# 'Old2' = 'New2' -# 'Old3' = 'New3'} -#----------------------------------------------------------------------- -function Update-TextByTable -{ - param ( - [Parameter(Mandatory=$true,ValueFromPipelineByPropertyName=$true)] - [string]$Path = $(throw '-Path is a required parameter.'), - [Parameter(Mandatory=$true,ValueFromPipelineByPropertyName=$true)] - [hashtable]$Replace = $(throw '-Replace is a required parameter.'), - [Parameter(Mandatory=$true,ValueFromPipelineByPropertyName=$true)] - [string[]]$Include = $(throw '-Include is a required parameter.'), - [string[]]$Exclude = "", - [Int32]$First = 100 - ) - Write-Verbose "Update-Text -Path $Path -Old $Old -New $New -Include $Include -Exclude $Exclude -First $First" - $Path = Remove-Suffix -String $Path -Remove "\" - if (Test-Path $Path) - { - Write-Verbose "Get-Childitem $Path -Include $Include -Exclude $Exclude -Recurse -Force | select -First $First" - $ConfigFiles=Get-Childitem $Path -Include $Include -Exclude $Exclude -Recurse -Force | select -First $First - Write-Verbose "ConfigFiles: $ConfigFiles" - $Count = 0 - foreach ($Item in $ConfigFiles) - { - Write-Verbose "Get-Content $Item.PSPath" - $fileLines = Get-Content $Item.PSPath - Write-Verbose "fileLines: $fileLines" - if($fileLines) - { - foreach($replaceItem in $Replace.GetEnumerator()) { - Write-Verbose "$fileLines.Replace($replaceItem.Key, $replaceItem.Value)" - $fileLines = $fileLines.Replace($replaceItem.Key, $replaceItem.Value) - } - Write-Verbose "Set-Content -Path $Item.PSPath -Value $fileLines -force" - Set-Content -Path $Item.PSPath -Value $fileLines -force - } - $Count = $Count + 1 - } - Write-Verbose "[Success] $Count items affected. $(Get-CurrentFile) at $(Get-CurrentLine)." - } - else - { - Write-Verbose "[OK] 0 items affected. $(Get-CurrentFile) at $(Get-CurrentLine)." - } -} -export-modulemember -function Update-TextByTable \ No newline at end of file diff --git a/scripts/azure-resources/System.psm1 b/scripts/azure-resources/System.psm1 deleted file mode 100644 index 5b7aae4..0000000 --- a/scripts/azure-resources/System.psm1 +++ /dev/null @@ -1,1500 +0,0 @@ -#----------------------------------------------------------------------- -# Add-Prefix [-String []] -# -# Example: .\Add-Prefix -String ello -Add H -# Result: Hello -#----------------------------------------------------------------------- -function Add-Prefix -{ - param ( - [Parameter(Mandatory=$true,ValueFromPipelineByPropertyName=$true)] - [string]$String = $(throw '-String is a required parameter.'), - [Parameter(Mandatory=$true,ValueFromPipelineByPropertyName=$true)] - [string]$Add = $(throw '-Add is a required parameter.') - ) - Write-Verbose "Add-Prefix -String $String -Add $Add" - [string]$ReturnValue = $String - if (-not (Compare-IsFirst -String $String -BeginsWith $Add)) - { - $ReturnValue = ($Add + $ReturnValue) - Write-Verbose "[Success] 1 items affected. $(Get-CurrentFile) at $(Get-CurrentLine)." - } - else - { - Write-Verbose "[OK] 0 items affected. $(Get-CurrentFile) at $(Get-CurrentLine). -String $String already has prefix of -Add $Add" - } - return $ReturnValue -} -export-modulemember -function Add-Prefix - -#----------------------------------------------------------------------- -# Add-Suffix [-String []] -# -# Example: .\Add-Suffix -String Hell -Add o -# Result: Hello -#----------------------------------------------------------------------- -function Add-Suffix -{ - param ( - [Parameter(Mandatory=$true,ValueFromPipelineByPropertyName=$true)] - [string]$String = $(throw '-String is a required parameter.'), - [Parameter(Mandatory=$true,ValueFromPipelineByPropertyName=$true)] - [string]$Add = $(throw '-Add is a required parameter.') - ) - Write-Verbose "Add-Suffix -String $String -Add $Add" - [string]$ReturnValue = $String - if (-not (Compare-IsLast -String $String -EndsWith $Add)) - { - $ReturnValue = ($String + $Add) - Write-Verbose "[Success] 1 items affected. $(Get-CurrentFile) at $(Get-CurrentLine)." - } - else - { - Write-Verbose "[OK] 0 items affected. $(Get-CurrentFile) at $(Get-CurrentLine). -String $String already has suffix of -Add $Add" - } - - return $ReturnValue -} -export-modulemember -function Add-Suffix - -#----------------------------------------------------------------------- -# Compare-IsFirst [-String []] -# -# Example: .\Compare-IsFirst -String Hell -EndsWith H -# Result: false -# Example: .\Compare-IsFirst -String Hello -Add H -# Result: Hello -#----------------------------------------------------------------------- -function Compare-IsFirst -{ - param ( - [Parameter(Mandatory=$true,ValueFromPipelineByPropertyName=$true)] - [string]$String = $(throw '-String is a required parameter.'), - [Parameter(Mandatory=$true,ValueFromPipelineByPropertyName=$true)] - [string]$BeginsWith = $(throw '-BeginsWith is a required parameter.') - ) - - Write-Verbose "Compare-IsFirst -String $String -EndsWith $EndsWith" - [Boolean]$ReturnValue = $false - if($BeginsWith.Length -lt $String.Length) - { - $StringBeginning = $String.SubString(0, $BeginsWith.Length).ToLower() - if ($StringBeginning.ToLower().Equals($BeginsWith.ToLower())) - { - $ReturnValue = $true - } - Write-Verbose "[Success] 1 items affected. $(Get-CurrentFile) at $(Get-CurrentLine)." - } - else - { - Write-Verbose "[OK] 0 items affected. $(Get-CurrentFile) at $(Get-CurrentLine)." - } - return $ReturnValue -} -export-modulemember -function Compare-IsFirst - -#----------------------------------------------------------------------- -# Compare-IsLast [-String []] -# -# Example: .\Compare-IsLast -String Hell -EndsWith H -# Result: false -# Example: .\Compare-IsLast -String Hello -Add H -# Result: Hello -#----------------------------------------------------------------------- -function Compare-IsLast -{ - param ( - [Parameter(Mandatory=$true,ValueFromPipelineByPropertyName=$true)] - [string]$String = $(throw '-String is a required parameter.'), - [Parameter(Mandatory=$true,ValueFromPipelineByPropertyName=$true)] - [string]$EndsWith = $(throw '-EndsWith is a required parameter.') - ) - Write-Verbose "Compare-IsLast -String $String -EndsWith $EndsWith" - [Boolean]$ReturnValue = $false - if($EndsWith.Length -lt $String.Length) - { - $StringEnding = $String.SubString(($String.Length - $EndsWith.Length), $EndsWith.Length) - if ($StringEnding.ToLower().Equals($EndsWith.ToLower())) - { - $ReturnValue = $true - } - Write-Verbose "[Success] 1 items affected. $(Get-CurrentFile) at $(Get-CurrentLine)." - } - else - { - Write-Verbose "[OK] 0 items affected. $(Get-CurrentFile) at $(Get-CurrentLine)." - } - - return $ReturnValue -} -export-modulemember -function Compare-IsLast - -#----------------------------------------------------------------------- -# Compress-Path [-Path []] [-File []] -# -# Example: .\Compress-Path \\source\path \\destination\path\file.zip -#----------------------------------------------------------------------- -function Compress-Path -{ - param ( - [Parameter(Mandatory=$true,ValueFromPipelineByPropertyName=$true)] - [string]$Path=$(throw '-Path is a required parameter.'), - [Parameter(Mandatory=$true,ValueFromPipelineByPropertyName=$true)] - [string]$File=$(throw '-File is a required parameter.') - ) - Write-Verbose "Compress-Path -Path $Path -File $File" - New-Path -Path $Path - Remove-File $File - [Reflection.Assembly]::LoadWithPartialName("System.IO.Compression.FileSystem") - [System.IO.Compression.ZipFile]::CreateFromDirectory($Path, $File) -} -export-modulemember -function Compress-Path - -#----------------------------------------------------------------------- -# Convert-PathSafe [-Path []] -# -# Example: .\Convert-PathSafe -Path \\source\path -#----------------------------------------------------------------------- -function Convert-PathSafe -{ - param ( - [Parameter(Mandatory=$true,ValueFromPipelineByPropertyName=$true)] - [string]$Path = $(throw '-Path is a required parameter.') - ) - Write-Verbose "Convert-PathSafe -Path $Path" - $Path = $Path.Trim() - $ReturnValue = $Path - $Path = Set-Unc -Path $Path - if(Test-Path -Path $Path) - { - $ReturnValue = Convert-Path -Path $Path - if (-not ($ReturnValue)) - { - $ReturnValue = $Path - Write-Verbose "[Warning] 0 items affected. $(Get-CurrentFile) at $(Get-CurrentLine). $(Get-CurrentFile) at $(Get-CurrentLine). -Path $Path didnt convert." - } - } - else - { - Write-Host "[Error] 0 items affected. $(Get-CurrentFile) at $(Get-CurrentLine). $(Get-CurrentFile) at $(Get-CurrentLine). -Path $Path does not exist." - } - return $ReturnValue -} -export-modulemember -function Convert-PathSafe - -#----------------------------------------------------------------------- -# Copy-Backup [-Path []] [-Destination []] -# -# Example: .\Copy-Backup -Path \\source\path -Destination \\destination\path -#----------------------------------------------------------------------- -function Copy-Backup -{ - param ( - [Parameter(Mandatory=$true,ValueFromPipelineByPropertyName=$true)] - [string]$Path = $(throw '-Path is a required parameter.'), - [Parameter(Mandatory=$true,ValueFromPipelineByPropertyName=$true)] - [string]$Destination = $(throw '-Destination is a required parameter.') - ) - Write-Verbose "Copy-Backup -Path $Path -Destination $Destination" - $Path = Remove-Suffix -String $Path -Remove "\" - New-Path -Path $Destination - [String]$BackupPath=[string]::Format("{0}\{1}", $Destination, (Get-Date).ToString("yyyy-MM-dd")) - if($Path) - { - if(-not (Test-Path -Path $BackupPath -PathType Container)){ - New-Path -Path $BackupPath - } - Copy-Recurse -Path $Path -Destination $BackupPath - Write-Verbose "[Success] 1 items affected. $(Get-CurrentFile) at $(Get-CurrentLine). -Path $Path to -Destination $BackupPath" - } - else - { - Write-Host "[Error] 0 items affected. $(Get-CurrentFile) at $(Get-CurrentLine). $(Get-CurrentFile) at $(Get-CurrentLine). -Path $Path does not exist." - } -} -export-modulemember -function Copy-Backup - -#----------------------------------------------------------------------- -# Copy-File [-Path []] [-Destination []] -# -# Example: .\Copy-File -Path \\source\path\File.name -Destination \\destination\path -#----------------------------------------------------------------------- -function Copy-File -{ - param ( - [Parameter(Mandatory = $True)] - [string]$Path = $(throw '-Path is a required parameter.'), - [Parameter(Mandatory = $True)] - [string]$Destination = $(throw '-Destination is a required parameter.'), - [string[]]$Include = "*.*", - [string[]]$Exclude = "", - [bool]$Overwrite = $true - ) - Write-Verbose "Copy-File -Path $Path -Destination $Destination -Overwrite $Overwrite" - $Destination = Set-Unc -Path $Destination - if(Test-File -Path $Path) - { - New-Path -Path $Destination - $DestinationAbsolute = $Destination - if(Test-Folder -Path $Destination) - { - $DestinationAbsolute = Convert-PathSafe -Path $Destination - } - $DestinationPathFile = $DestinationAbsolute - $FolderArray = $Path.Split('\') - if($FolderArray.Count -gt 0) - { - $DestinationPathFile = Join-Path $DestinationAbsolute $FolderArray[$FolderArray.Count-1] - } - if((-not (Test-Path $DestinationPathFile -PathType Leaf)) -or ($Overwrite -eq $true)) - { - try{ - Copy-Item -Path $Path -Destination $DestinationAbsolute -Include $Include -Exclude $Exclude -Force - } - catch{ - Write-Host "[Error] 0 items affected. $(Get-CurrentFile) at $(Get-CurrentLine). -Path $Path does not exist." - } - } - Write-Verbose "[Success] 1 items affected. $(Get-CurrentFile) at $(Get-CurrentLine). -Path $Path to -Destination $DestinationAbsolute" - } - else - { - Write-Host "[Error] 0 items affected. $(Get-CurrentFile) at $(Get-CurrentLine). -Path $Path does not exist." - } -} -export-modulemember -function Copy-File - -#----------------------------------------------------------------------- -# Copy-Recurse [-Source []] [-Destination []] -# [-Include [] [-Exclude []] -# -# Example: .\Copy-Recurse \\source\path \\destination\path -#----------------------------------------------------------------------- -function Copy-Recurse -{ - param ( - [Parameter(Mandatory=$true,ValueFromPipelineByPropertyName=$true)] - [string]$Path = $(throw '-Source is a required parameter.'), - [Parameter(Mandatory=$true,ValueFromPipelineByPropertyName=$true)] - [string]$Destination = $(throw '-Destination is a required parameter.'), - [string[]]$Include = "*.*", - [string[]]$Exclude = "", - [Int32]$First = 1000, - [bool]$Overwrite=$True, - [bool]$Clean = $False - ) - Write-Verbose "Copy-Recurse -Path $Path -Destination $Destination -Include $Include -Exclude $Exclude -First $ -Overwrite $Overwrite -Clean $Clean" - $Affected = 0 - $Path = Set-Unc -Path $Path - if (Test-Path $Path) - { - $PathAbsolute = Convert-PathSafe -Path $Path - # Optionally Clean - if($Clean -eq $True) { Remove-Path -Path $Destination } - New-Path -Path $Destination - $DestinationAbsolute = $Destination - if(Test-Path $Destination) { $DestinationAbsolute=Convert-PathSafe -Path $Destination } - $Items = Get-ChildItem -Path $PathAbsolute -Recurse -Include $Include -Exclude $Exclude | where { ! $_.PSIsContainer } - ForEach ($Item in $Items) { - $PathArray = $PathAbsolute.Split('\') - $Folder = $DestinationAbsolute - for ($count=1; $count -lt $PathArray.length-1; $count++) { - $Subfolder = $PathArray[$count] - $Folder = Join-Path $Folder $Subfolder - if (($Folder.Length > 0) -and (-not (Test-Path $Folder))) { - Write-Verbose "New-Item -ItemType directory -Force -Path $Folder" - New-Item -ItemType directory -Force -Path $Folder - } - } - $DirName = $Item.DirectoryName - $Position = $DirName.IndexOf($PathAbsolute) - $PathSegment = $DirName.SubString($Position + $PathAbsolute.Length) - $NewPath = Join-Path $DestinationAbsolute $PathSegment - Copy-File -Path $Item.FullName -Destination $NewPath -Overwrite $Overwrite - $Affected = $Affected + 1 - } - Write-Verbose "[Success] $Affected items affected. $(Get-CurrentFile) at $(Get-CurrentLine)." - } - else - { - Write-Host "[Error] 0 items affected. $(Get-CurrentFile) at $(Get-CurrentLine). -Path $Path does not exist." - } -} -export-modulemember -function Copy-Recurse - -#----------------------------------------------------------------------- -# Expand-File [-Path []] [-File []] -# -# Example: .\Expand-File \\source\path\file.zip \\destination\path -#----------------------------------------------------------------------- -function Expand-File -{ - param ( - [Parameter(Mandatory=$true,ValueFromPipelineByPropertyName=$true)] - [string]$Path=$(throw '-Path is a required parameter.'), - [Parameter(Mandatory=$true,ValueFromPipelineByPropertyName=$true)] - [string]$File=$(throw '-File is a required parameter.') - ) - Write-Verbose "Expand-Zip -Path $Path -File $File" - New-Path -Path $Path - [Reflection.Assembly]::LoadWithPartialName("System.IO.Compression.FileSystem") - [System.IO.Compression.ZipFile]::ExtractToDirectory($File, $Path) -} -export-modulemember -function Expand-File - -#----------------------------------------------------------------------- -# Find-File [-Path []] [-File []] -# -# Example: .\Find-File \\source\path\file.zip \\destination\path -#----------------------------------------------------------------------- -function Find-File -{ - param ( - [Parameter(Mandatory=$true,ValueFromPipelineByPropertyName=$true)] - [string]$Path=$(throw '-Path is a required parameter.'), - [Parameter(Mandatory=$true,ValueFromPipelineByPropertyName=$true)] - [string]$File=$(throw '-File is a required parameter.'), - [Int32]$First=1 - ) - Write-Verbose "Find-Zip -Path $Path -File $File" - Get-Childitem -Path $Path -Include $File -Recurse| select -First $First -} -export-modulemember -function Find-File - -#----------------------------------------------------------------------- -# Get-AssemblyStrongName -# -# Example: Get-AssemblyStrongName -#----------------------------------------------------------------------- -function Get-AssemblyStrongName($assemblyPath) -{ - [System.Reflection.AssemblyName]::GetAssemblyName($assemblyPath).FullName -} -export-modulemember -function Get-AssemblyStrongName - -#----------------------------------------------------------------------- -# Get-CurrentLine -# -# Example: Get-CurrentLine -#----------------------------------------------------------------------- -function Get-CurrentLine { - $MyInvocation.ScriptLineNumber -} -export-modulemember -function Get-CurrentLine - -#----------------------------------------------------------------------- -# Get-CurrentFile -# -# Example: Get-CurrentFile -#----------------------------------------------------------------------- -function Get-CurrentFile { - $MyInvocation.ScriptName -} -export-modulemember -function Get-CurrentFile - -#----------------------------------------------------------------------- -# Get-FilesByString -# -# Example: Get-FilesByString -#----------------------------------------------------------------------- -function Get-FilesByString { - param ( - [Parameter(Mandatory=$true,ValueFromPipelineByPropertyName=$true)] - [string]$Path = $(throw '-Path is a required parameter.'), - [string]$String = $(throw '-String is a required parameter.'), - [string[]]$Include = ("*.*"), - [string[]]$Exclude = "" - ) - Write-Host "Get-FilesByString -Path $Path -String $String -Include $Include -Exclude $Exclude" - $Path = Set-Unc -Path $Path - - $ReturnData = Get-Childitem -Path $Path -Include $Include -Exclude $Exclude -Recurse | Select-String -pattern $String | group path | select name - - return $ReturnData -} -export-modulemember -function Get-FilesByString - -#----------------------------------------------------------------------- -# Get-SystemFolders -# -# Example: Get-SystemFolder -#----------------------------------------------------------------------- -function Get-SystemFolders -{ - param ( - ) - Write-Verbose "Get-SystemFolders" - $SpecialFolders = @{} - $names = [Environment+SpecialFolder]::GetNames([Environment+SpecialFolder]) - foreach($name in $names) - { - if($path = [Environment]::GetFolderPath($name)){ - $SpecialFolders[$name] = $path - } - else - { - Write-Verbose "[Warning] 0 items affected. $(Get-CurrentFile) at $(Get-CurrentLine)." - } - } - return $SpecialFolders -} -export-modulemember -function Get-SystemFolders - -#----------------------------------------------------------------------- -# Get-SystemFolder [-Name []] -# Keys: Desktop,Programs,MyDocuments,Personal,Favorites,Startup,Recent,SendTo,StartMenu,MyMusic,MyVideos,DesktopDirectory,NetworkShortcuts,Fonts -# Templates,CommonStartMenu,CommonPrograms,CommonStartup,CommonDesktopDirectory,ApplicationData,PrinterShortcuts,LocalApplicationData,InternetCache -# Cookies,History,CommonApplicationData,Windows,System,ProgramFiles,MyPictures,UserProfile,SystemX86,ProgramFilesX86 -# CommonProgramFiles,CommonProgramFilesX86,CommonTemplates,CommonDocuments,CommonAdminTools,AdminTools,CommonMusic,CommonPictures,CommonVideos,ResourcesCDBurning -# Example: Get-SystemFolder -Name 'UserProfile' -#----------------------------------------------------------------------- -function Get-SystemFolder -{ - param ( - [Parameter(Mandatory=$true,ValueFromPipelineByPropertyName=$true)] - [String]$Name=$(throw '-Folder is a required parameter.') - ) - Write-Verbose "Get-SystemFolder -Folder $Folder" - if($path = [Environment]::GetFolderPath($name)){ - $Folder = $path - } - else - { - Write-Verbose "[Warning] 0 items affected. $(Get-CurrentFile) at $(Get-CurrentLine)." - } - return $Folder -} -export-modulemember -function Get-SystemFolder - -#----------------------------------------------------------------------- -# Move-Path [-Path []] [-Destination []] -# [-Exclude []] -# -# Example: .\Move-Path -Path \\source\path -#----------------------------------------------------------------------- -function Move-Path -{ - param ( - [Parameter(Mandatory=$true,ValueFromPipelineByPropertyName=$true)] - [string]$Path = $(throw '-Path is a required parameter.'), - [Parameter(Mandatory=$true,ValueFromPipelineByPropertyName=$true)] - [string]$Destination = $(throw '-Destination is a required parameter.'), - [string]$Exclude = "" - ) - Write-Verbose "Move-Path -Path $Path -Destination $Destination" - $Path = Remove-Suffix -String $Path -Remove "\" - if (test-folder -Path $Path) - { - Remove-Path -Destination $Destination - New-Path -Destination $Destination - Copy-Recurse -Path $Path -Destination $Destination -Exclude $Exclude - Remove-Path -Destination $Path - Write-Verbose "[Success] 1 items affected. $(Get-CurrentFile) at $(Get-CurrentLine). -Path $Path moved to -Destination $Destination" - } - else - { - Write-Host "[Error] 0 items affected. $(Get-CurrentFile) at $(Get-CurrentLine). -Path $Path does not exist." - } -} -export-modulemember -function Move-Path - -#----------------------------------------------------------------------- -# New-Path [-Path []] -# -# Example: .\New-Path \\source\path -#----------------------------------------------------------------------- -function New-Path -{ - param ( - [Parameter(Mandatory=$true,ValueFromPipelineByPropertyName=$true)] - [string]$Path = $(throw '-Path is a required parameter.'), - [bool]$Clean=$false - ) - Write-Verbose "New-Path -Path $Path" - [String]$Folder = "" - $Path = Remove-Suffix -String $Path -Remove "\" - if ($Clean) {Remove-Path -Path $Path} - if (-not (test-path $Path)) { - if (Test-Unc $Path) - { - $PathArray = $Path.Split('\') - foreach($item in $PathArray) - { - if($item.Length -gt 0) - { - if($Folder.Length -lt 1) - { - $Folder = "\\$item" - } - else - { - $Folder = "$Folder\$item" - if (-not (Test-Path $Folder)) { - New-Item -ItemType directory -Path $Folder -Force - } - } - } - } - } - else - { - New-Item -ItemType directory -Path $Path -Force - } - } -} -export-modulemember -function New-Path - -#----------------------------------------------------------------------- -# Redo-Path [-Path []] [-Destination []] -# [-Exclude []] -# -# Example: .\Redo-Path -Path \\source\path -#----------------------------------------------------------------------- -function Redo-Path -{ - param ( - [Parameter(Mandatory=$true,ValueFromPipelineByPropertyName=$true)] - [string]$Path = $(throw '-Path is a required parameter.'), - [Parameter(Mandatory=$true,ValueFromPipelineByPropertyName=$true)] - [string]$Destination = $(throw '-Destination is a required parameter.'), - [string]$Exclude = "" - ) - Write-Verbose "Redo-Path -Path $Path -Destination $Destination" - $Path = Remove-Suffix -String $Path -Remove "\" - Remove-Path -Destination $Path - New-Path -Destination $Path - Copy-Recurse -Path $Path -Destination $Destination -Exclude $Exclude - Write-Verbose "[Success] 1 items affected. $(Get-CurrentFile) at $(Get-CurrentLine). -Path $Path to -Destination $Destination" -} -export-modulemember -function Redo-Path - -#----------------------------------------------------------------------- -# Remove-File [-File []] -# -# Example: .\Remove-File \\source\path\file.txt -#----------------------------------------------------------------------- -function Remove-File -{ - param ( - [Parameter(Mandatory=$true,ValueFromPipelineByPropertyName=$true)] - [string]$Path=$(throw '-Path is a required parameter.') - ) - Write-Verbose "Remove-File -Path $Path" - if (Test-File -Path $Path) { - Remove-Item -Path $Path -Force - Write-Verbose "[Success] 1 items affected. $(Get-CurrentFile) at $(Get-CurrentLine). -Path $Path removed." - } - else - { - Write-Host "[Error] 0 items affected. $(Get-CurrentFile) at $(Get-CurrentLine). -Path $Path does not exist." - } -} -export-modulemember -function Remove-File - -#----------------------------------------------------------------------- -# Remove-Path [-Path []] -# [-Include [] [-Exclude []] -# -# Example: .\Remove-Path -Path \\source\path -#----------------------------------------------------------------------- -function Remove-Path -{ - param ( - [Parameter(Mandatory=$true,ValueFromPipelineByPropertyName=$true)] - [string]$Path = $(throw '-Path is a required parameter.'), - [string[]]$Include = "*.*", - [string[]]$Exclude = "", - [Int16]$Retention = 1, - [Int32]$First = 1000 - ) - Write-Verbose "Remove-Path -Path $Path -Include $Include -Exclude $Exclude -Retention $Retention -First $First" - $Path = Remove-Suffix -String $Path -Remove "\" - if (test-folder -Path $Path) { - $ErrorActionPreferenceBackup = $ErrorActionPreference - $ErrorActionPreference = 'SilentlyContinue' - Get-ChildItem -Path $Path -Include $Include -Exclude $Exclude -Recurse | Where-Object {($_.PSIsContainer) -and ($_.lastwritetime -le (get-date).addDays(($Retention*-1)))} | select -First $First | Remove-Item -Force -Recurse - Remove-Item $Path -Recurse -Force - $ErrorActionPreference = $ErrorActionPreferenceBackup - Write-Verbose "[Success] 1 items affected. $(Get-CurrentFile) at $(Get-CurrentLine). -Path $Path removed." - } - else - { - Write-Verbose "[Warning] 0 items affected. $(Get-CurrentFile) at $(Get-CurrentLine)." - } -} -export-modulemember -function Remove-Path - -#----------------------------------------------------------------------- -# Remove-Subfolders [-Path []] -# [-Include [] [-Exclude []] -# -# Example: .\Remove-Subfolders -Path \\source\path -#----------------------------------------------------------------------- -function Remove-Subfolders -{ - param ( - [Parameter(Mandatory=$true,ValueFromPipelineByPropertyName=$true)] - [string]$Path = $(throw '-Path is a required parameter.'), - [Parameter(Mandatory=$true,ValueFromPipelineByPropertyName=$true)] - [string]$Subfolder = $(throw '-Subfolder is a required parameter.'), - [Int32]$First = 1000 - ) - Write-Verbose "Remove-Subfolders -Path $Path -Subfolder $Subfolder -First $First" - $Path = Set-Unc -Path $Path - - if (test-folder -Path $Path) { - $Affected = 0 - if(Test-Unc -Path $Path) - { - $Folders=Get-ChildItem $Path -Recurse | Where-Object {($_.Name -EQ $Subfolder) -and ($_.PSIsContainer)} | select -First $First - foreach ($Folder in $Folders) { - if ($Folder.FullName) - { - [String]$FolderToRemove=Add-Suffix -String $Folder.FullName -Add "\" - Remove-Path -Path $FolderToRemove - $Affected = $Affected + 1 - } - } - } - else - { - $Remove = Add-Suffix -String $Path -Add '\' - $Remove = Add-Suffix -String $Remove -Add $Subfolder - Remove-Path -Path $Remove - $Affected = 1 - } - Write-Verbose "[Success] $Affected items affected. $(Get-CurrentFile) at $(Get-CurrentLine). -Path $Path -Subfolder $Subfolder removed." - } - else - { - Write-Verbose "[Warning] 0 items affected. $(Get-CurrentFile) at $(Get-CurrentLine). -Path $Path does not exist." - } -} -export-modulemember -function Remove-Subfolders - -#----------------------------------------------------------------------- -# Remove-Recurse [-Source []] [-Destination []] -# [-Include [] [-Exclude []] -# -# Example: .\Remove-Recurse \\source\path \\destination\path -#----------------------------------------------------------------------- -function Remove-Recurse -{ - param ( - [Parameter(Mandatory=$true,ValueFromPipelineByPropertyName=$true)] - [string]$Path = $(throw '-Source is a required parameter.'), - [string[]]$Include = "*.*", - [string[]]$Exclude = "", - [Int32]$First = 1000 - ) - Write-Verbose "Remove-Recurse -Path $Path -Include $Include -Exclude $Exclude" - $Path = Remove-Suffix -String $Path -Remove "\" - if (Test-Path $Path) - { - $PathAbsolute = Convert-PathSafe -Path $Path - $Items = Get-ChildItem -Path $PathAbsolute -Recurse -Include $Include -Exclude $Exclude | where { ! $_.PSIsContainer } - $Affected = 0 - ForEach ($Item in $Items) { - Remove-File -Path $Item - $Affected = $Affected + 1 - } - Write-Verbose "[Success] $Affected items affected. $(Get-CurrentFile) at $(Get-CurrentLine). -Path $Path." - } - else - { - Write-Verbose "[Warning] 0 items affected. $(Get-CurrentFile) at $(Get-CurrentLine). -Path $Path does not exist." - } -} -export-modulemember -function Remove-Recurse - -#----------------------------------------------------------------------- -# Remove-Prefix [-String []] -# -# Example: .\Remove-Prefix -String Hell -Remove o -# Result: Hello -#----------------------------------------------------------------------- -function Remove-Prefix -{ - param ( - [Parameter(Mandatory=$true,ValueFromPipelineByPropertyName=$true)] - [string]$String = $(throw '-String is a required parameter.'), - [Parameter(Mandatory=$true,ValueFromPipelineByPropertyName=$true)] - [string]$Remove = $(throw '-Remove is a required parameter.') - ) - Write-Verbose "Remove-Prefix -String $String -Remove $Remove" - [string]$ReturnValue = $String - if (Compare-IsFirst -String $String -BeginsWith $Remove) - { - $ReturnValue = $String.Substring($Remove.Length, $String.Length - $Remove.Length) - Write-Verbose "[Success] 1 items affected. $(Get-CurrentFile) at $(Get-CurrentLine)." - } - else - { - Write-Verbose "[OK] 0 items affected. $(Get-CurrentFile) at $(Get-CurrentLine). -String $String already has prefix of -Remove $Remove" - } - - return $ReturnValue -} -export-modulemember -function Remove-Prefix - -#----------------------------------------------------------------------- -# Remove-Suffix [-String []] -# -# Example: .\Remove-Suffix -String Hell -Remove o -# Result: Hello -#----------------------------------------------------------------------- -function Remove-Suffix -{ - param ( - [Parameter(Mandatory=$true,ValueFromPipelineByPropertyName=$true)] - [string]$String = $(throw '-String is a required parameter.'), - [Parameter(Mandatory=$true,ValueFromPipelineByPropertyName=$true)] - [string]$Remove = $(throw '-Remove is a required parameter.') - ) - Write-Verbose "Remove-Suffix -String $String -Remove $Remove" - [string]$ReturnValue = $String - if($String) - { - if (Compare-IsLast -String $String -EndsWith $Remove) - { - $ReturnValue = $ReturnValue.Substring(0, $String.Length - $Remove.Length) - } - Write-Verbose "[Success] 1 items affected. $(Get-CurrentFile) at $(Get-CurrentLine)." - } - else - { - Write-Verbose "[OK] 0 items affected. $(Get-CurrentFile) at $(Get-CurrentLine). -String $String already has suffix of -Remove $Remove" - } - - return $ReturnValue -} -export-modulemember -function Remove-Suffix - -#----------------------------------------------------------------------- -# Remove-Element [-Path []] -# -# Example: .\Remove-Element -Value "" -# -XPath "//msb:None/msb:Generator" -# -Namespace @{msb = "http://schemas.microsoft.com/developer/msbuild/2003"} -# -# Called: $XMLValue = [xml](Get-Content $path) -# $Namespace = @{msb = 'http://schemas.microsoft.com/developer/msbuild/2003'} -# Remove-Element $XMLValue -XPath '//msb:None/msb:Generator' -Namespace $Namespace -# $proj.Save($path) -#----------------------------------------------------------------------- -function Remove-Element -{ - param ( - [Parameter(Mandatory=$true,ValueFromPipelineByPropertyName=$true)] - [xml]$Value=$(throw '-Value is a required parameter.'), - [Parameter(Mandatory=$true,ValueFromPipelineByPropertyName=$true)] - [String]$XPath=$(throw '-Value is a required parameter.'), - [Parameter(Mandatory=$true,ValueFromPipelineByPropertyName=$true)] - [String]$Namespace=$(throw '-Value is a required parameter.') - ) - Write-Verbose ".\Remove-Element -Value $Value -XPath $XPath -Namespace $Namespace -SingleNode" - $nodes = @(Select-Xml $XPath $Value -Namespace $Namespace | Foreach {$_.Node}) - if (!$nodes) { Write-Verbose "RemoveElement: XPath $XPath not found" } - if ($singleNode -and ($nodes.Count -gt 1)) { - throw "XPath $XPath found multiple nodes" - } - $Count = 0 - foreach ($node in $nodes) - { - $parentNode = $node.ParentNode - [void]$parentNode.RemoveChild($node) - $Count = $Count + 1 - } - Write-Verbose "[Success] $Count items affected. $(Get-CurrentFile) at $(Get-CurrentLine)." -} -export-modulemember -function Remove-Element - -#----------------------------------------------------------------------- -# Remove-ContentsByTagContains [-Path []] -# [-Open [] [-Close []] -# -# Example: .\Remove-ContentsByTagContains \\source\path \\destination\path -# GlobalSection(TeamFoundationVersionControl) = preSolution -# EndGlobalSection -#----------------------------------------------------------------------- -function Remove-ContentsByTag -{ - param ( - [Parameter(Mandatory=$true,ValueFromPipelineByPropertyName=$true)] - [string]$Path = $(throw '-Path is a required parameter.'), - [Parameter(Mandatory=$true,ValueFromPipelineByPropertyName=$true)] - [string]$Open = $(throw '-Open is a required parameter.'), - [Parameter(Mandatory=$true,ValueFromPipelineByPropertyName=$true)] - [string]$Close = $(throw '-Close is a required parameter.'), - [string[]]$Include = "*.*", - [string[]]$Exclude = "", - [Int32]$First = 100 - ) - Write-Verbose "Remove-ContentsByTag -Path $Path -Open $Open -Close $Close -Include $Include -Exclude $Exclude -First $First" - $Path = Remove-Suffix -String $Path -Remove "\" - if (Test-Path $Path) - { - $Open = $Open.Trim() - $Close = $Close.Trim() - $Files = Get-Childitem -Path $Path -Include $Include -Exclude $Exclude -Recurse -Force | select -First $First - ForEach ($File in $Files) - { - [Int32]$OpenIndex = -1 - [Int32]$CloseIndex = -1 - $Content=Get-Content $File.PSPath - # Search for matches - For([Int32]$Count = 0; $Count -lt $Content.Length; $Count++) - { - $CurrentLine = $Content[$Count].Trim() - If(($OpenIndex -eq -1) -and ($CurrentLine -eq $Open)) - { - $OpenIndex = $Count - } - ElseIf(($OpenIndex -gt -1) -and ($CurrentLine -eq $Close)) - { - $CloseIndex = $Count - Break - } - } - # Evaluate search - If(($OpenIndex -gt -1) -and ($OpenIndex -lt $CloseIndex)) - { - # Match Found Remove block. - $NewContent = ($Content | Select -First $OpenIndex) + ($Content | select -Last ($Content.Length - $CloseIndex - 1)) - } - else - { - # No Match Found - $NewContent = $Content - } - Set-Content $File.PSPath -Value $NewContent - } - Write-Verbose "[Success] 1 items affected. $(Get-CurrentFile) at $(Get-CurrentLine)." - } - else - { - Write-Verbose "[OK] 0 items affected. $(Get-CurrentFile) at $(Get-CurrentLine)." - } -} -export-modulemember -function Remove-ContentsByTag - -#----------------------------------------------------------------------- -# Remove-ContentsByTagContains [-Path []] -# [-Open [] [-Close []] -# -# Example: .\Remove-ContentsByTagContains \\source\path \\destination\path -# GlobalSection(TeamFoundationVersionControl) = preSolution -# EndGlobalSection -#----------------------------------------------------------------------- -function Remove-ContentsByTagContains -{ - param ( - [Parameter(Mandatory=$true,ValueFromPipelineByPropertyName=$true)] - [string]$Path = $(throw '-Path is a required parameter.'), - [Parameter(Mandatory=$true,ValueFromPipelineByPropertyName=$true)] - [string]$Open = $(throw '-Open is a required parameter.'), - [Parameter(Mandatory=$true,ValueFromPipelineByPropertyName=$true)] - [string]$Close = $(throw '-Close is a required parameter.'), - [Parameter(Mandatory=$true,ValueFromPipelineByPropertyName=$true)] - [string]$Contains = $(throw '-Contains is a required parameter.'), - [string[]]$Include = "*.*", - [string[]]$Exclude = "", - [Int32]$First = 100 - ) - Write-Verbose "Remove-ContentsByTagContains -Path $Path -Open $Open -Close $Close -Contains $Contains -Include $Include -Exclude $Exclude -First $First" - $Path = Remove-Suffix -String $Path -Remove "\" - if (Test-Path $Path) - { - $Open = $Open.Trim() - $Close = $Close.Trim() - $Contains = $Contains.Trim() - - $Files = Get-Childitem -Path $Path -Include $Include -Exclude $Exclude -Recurse -Force | select -First $First - ForEach ($File in $Files) - { - [Int32]$OpenIndex = -1 - [Int32]$ContainsIndex = -1 - [Int32]$CloseIndex = -1 - $Content=Get-Content $File.PSPath - # Search for matches - For([Int32]$Count = 0; $Count -lt $Content.Length; $Count++) - { - $CurrentLine = $Content[$Count].Trim() - If ($CurrentLine -like "*$Open*") - { - If($OpenIndex -gt -1) - { - # Fail: Block did not contain -Content and/or -Open was found before -Close. Reset for next open tag match. - $ContainsIndex = -1 - $CloseIndex = -1 - } - $OpenIndex = $Count - }ElseIf($OpenIndex -gt -1) - { - If($CurrentLine -like "*$Contains*") - { - $ContainsIndex = $Count - }ElseIf(($ContainsIndex -gt -1) -and ($CurrentLine -like "*$Close*")) - { - # Success, block starts with -Open, ends with -Close and includes -Contains - $CloseIndex = $Count - Break - } - } - } - # Any matches? - If(($OpenIndex -gt -1) -and ($ContainsIndex -gt $OpenIndex) -and ($CloseIndex -gt $ContainsIndex)) - { - If($CloseIndex -eq ($OpenIndex + 2)) - { - # Match Found with single element. Remove Block. - $NewContent = ($Content | Select -First $OpenIndex) + ($Content | select -Last ($Content.Length - $CloseIndex - 1)) - } - Else - { - # Match Found with multiple elements. Remove Line Only. - $NewContent = ($Content | Select -First $ContainsIndex) + ($Content | select -Last ($Content.Length - $ContainsIndex -1)) - } - } - else - { - # No Match Found - $NewContent = $Content - } - Set-Content $File.PSPath -Value $NewContent - } - Write-Verbose "[Success] 1 items affected. $(Get-CurrentFile) at $(Get-CurrentLine)." - } - else - { - Write-Verbose "[OK] 0 items affected. $(Get-CurrentFile) at $(Get-CurrentLine)." - } -} -export-modulemember -function Remove-ContentsByTagContains - -#----------------------------------------------------------------------- -# Rename-File [-File []] -# -# Example: .\Rename-File -Path ($StagingZipPath + 'root.vstbak') -NewName root.vstemplate -Force -#----------------------------------------------------------------------- -function Rename-File -{ - param ( - [Parameter(Mandatory=$true,ValueFromPipelineByPropertyName=$true)] - [string]$Path=$(throw '-Path is a required parameter.'), - [string]$NewName=$(throw '-NewName is a required parameter.') - ) - Write-Verbose "Rename-File -Path $Path -NewName $NewName" - if (Test-File -Path $Path) { - Rename-Item -Path $Path -NewName $NewName -Force - Write-Verbose "[Success] 1 items affected. $(Get-CurrentFile) at $(Get-CurrentLine). -Path $Path removed." - } - else - { - Write-Host "[Error] 0 items affected. $(Get-CurrentFile) at $(Get-CurrentLine). -Path $Path does not exist." - } -} -export-modulemember -function Rename-File - -#----------------------------------------------------------------------- -# Set-ReadOnly [-Path []] [-ReadOnly []] -# -# Example: .\Set-ReadOnly -Path \\source\path\File.name -ReadOnly $False -#----------------------------------------------------------------------- -function Set-ReadOnly -{ - param ( - [Parameter(Mandatory = $True)] - [string]$Path = $(throw '-Path is a required parameter.'), - [bool]$ReadOnly = $True, - [string]$ErrorPreference = 'SilentlyContinue' - ) - Write-Verbose "Set-ReadOnly -Path $Path -ReadOnly $ReadOnly -ErrorPreference $ErrorPreference" - $Path = Remove-Suffix -String $Path -Remove "\" - if(test-path $Path) - { - $PathAbsolute = Convert-PathSafe -Path $Path - if (Test-Path $PathAbsolute -PathType Leaf) - { - $ErrorActionPreferenceBackup = $ErrorActionPreference - $ErrorActionPreference = $ErrorPreference - Set-ItemProperty $PathAbsolute -name IsReadOnly -value $ReadOnly -Force - $ErrorActionPreference = $ErrorActionPreferenceBackup - } - Write-Verbose "[Success] 1 items affected. $(Get-CurrentFile) at $(Get-CurrentLine). -Path $Path set." - } - else - { - Write-Host "[Error] 0 items affected. $(Get-CurrentFile) at $(Get-CurrentLine). -Path $Path does not exist." - } -} -export-modulemember -function Set-ReadOnly - -#----------------------------------------------------------------------- -# Set-SystemFolderDrives -# -# Example: Set-SystemFolderDrives -#----------------------------------------------------------------------- -function Set-SystemFolderDrives -{ - param ( - ) - Write-Verbose "Set-SystemFolderDrives" - - $SpecialFolders = @{} - $names = [Environment+SpecialFolder]::GetNames([Environment+SpecialFolder]) - foreach($name in $names) - { - if($path = [Environment]::GetFolderPath($name)){ - $SpecialFolders[$name] = $path - New-PSDrive -Name $name -PSProvider FileSystem -Root $path - } - } - # #TBD: Find the 10 Largest Files in the Documents Folder - # gci Personal: -Recurse -Force -ea SilentlyContinue | - # Sort-Object -Property Length -Descending | - # Select-Object -First 10 | - # Format-Table -AutoSize -Wrap -Property ` - # Length,LastWriteTime,FullName - return $SpecialFolders -} -export-modulemember -function Set-SystemFolderDrives - -#----------------------------------------------------------------------- -# Test-File [-Path []] -# -# Example: .\Test-File -Path \\source\path -#----------------------------------------------------------------------- -function Test-File -{ - param ( - [Parameter(Mandatory=$true,ValueFromPipelineByPropertyName=$true)] - [string]$Path = $(throw '-Path is a required parameter.') - ) - Write-Verbose "Test-File -Path $Path" - [bool]$ReturnValue = $false - if(Test-Path -Path $Path -PathType Leaf) - { - $ReturnValue = $true - } - else - { - Write-Verbose "[Warning] 0 items affected. $(Get-CurrentFile) at $(Get-CurrentLine). -Path $Path does not exist or is not a File." - } - return $ReturnValue -} -export-modulemember -function Test-File - -#----------------------------------------------------------------------- -# Test-Folder [-Path []] -# -# -# Example: .\Test-Folder -Path \\source\path -#----------------------------------------------------------------------- -function Test-Folder -{ - param ( - [Parameter(Mandatory=$true,ValueFromPipelineByPropertyName=$true)] - [string]$Path = $(throw '-Path is a required parameter.') - ) - Write-Verbose "Test-Folder -Path $Path" - [bool]$ReturnValue = $false - if(test-path -Path $Path -PathType Container) - { - $ReturnValue = $true - } - else - { - Write-Verbose "[Warning] 0 items affected. $(Get-CurrentFile) at $(Get-CurrentLine). -Path $Path does not exist or is not a Folder." - } - return $ReturnValue -} -export-modulemember -function Test-Folder - -#----------------------------------------------------------------------- -# Test-PathEmpty [-Path []] -# -# Example: .\Test-PathEmpty -Path \\source\path -#----------------------------------------------------------------------- -function Test-PathEmpty -{ - param ( - [Parameter(Mandatory=$true,ValueFromPipelineByPropertyName=$true)] - [string]$Path = $(throw '-Path is a required parameter.') - ) - Write-Verbose "Test-PathEmpty -Path $Path" - [bool]$ReturnValue = $false - if((Get-ChildItem $Path -force | Select-Object -First 1 | Measure-Object).Count -eq 0) - { - $ReturnValue = $true - } - else - { - Write-Host "[Error] 0 items affected. $(Get-CurrentFile) at $(Get-CurrentLine). -Path $Path does not exist." - } - return $ReturnValue -} -export-modulemember -function Test-PathEmpty - -#----------------------------------------------------------------------- -# Set-Unc [-Path []] -# -# Example: .\Set-Unc -Path \\source\path -#----------------------------------------------------------------------- -function Set-Unc -{ - param ( - [Parameter(Mandatory=$true,ValueFromPipelineByPropertyName=$true)] - [string]$Path = $(throw '-Path is a required parameter.') - ) - Write-Verbose "Set-Unc -Path $Path" - $Path = $Path.Trim() - $Path = Remove-Suffix -String $Path -Remove '\' - if(-not ($Path.Contains(':\') -or $Path.Contains('.\') -or (Compare-IsFirst -String $Path -BeginsWith '\'))) - { - $ReturnValue = Add-Prefix -String $Path -Add '\\' - } - else - { - $ReturnValue = $Path - Write-Verbose "[OK] 0 items affected. $(Get-CurrentFile) at $(Get-CurrentLine). -Path $Path already a UNC, drive letter, absolute or relative path." - } - return $ReturnValue -} -export-modulemember -function Set-Unc - -#----------------------------------------------------------------------- -# Test-Unc [-Path []] -# -# -# Example: .\Test-Unc -Path \\source\path -#----------------------------------------------------------------------- -function Test-Unc -{ - param ( - [Parameter(Mandatory=$true,ValueFromPipelineByPropertyName=$true)] - [string]$Path = $(throw '-Path is a required parameter.') - ) - Write-Verbose "Test-Unc -Path $Path" - [bool]$ReturnValue = $false - if(($Path.Contains('\\')) -and (-not ($Path.Contains(':\')))) - { - $ReturnValue = $true - } - else - { - Write-Verbose "[OK] 0 items affected. $(Get-CurrentFile) at $(Get-CurrentLine)." - } - return $ReturnValue -} -export-modulemember -function Test-Unc - -#----------------------------------------------------------------------- -# Update-LineByContains [-Path []] -# [-Contains [] [-Close []] -# -# Example: .\Update-LineByContains -Path \\source\path -Include AssemblyInfo.cs -Contains 'AssemblyVersion(' -Line '[assembly: AssemblyVersion("5.20.07")]' -#----------------------------------------------------------------------- -function Update-LineByContains -{ - param ( - [Parameter(Mandatory=$true,ValueFromPipelineByPropertyName=$true)] - [string]$Path = $(throw '-Path is a required parameter.'), - [Parameter(Mandatory=$true,ValueFromPipelineByPropertyName=$true)] - [string]$Contains = $(throw '-Contains is a required parameter.'), - [Parameter(Mandatory=$true,ValueFromPipelineByPropertyName=$true)] - [string]$Line = $(throw '-Line is a required parameter.'), - [string[]]$Include = "*.*", - [string[]]$Exclude = "", - [Int32]$First = 100 - ) - Write-Host "Update-LineByContains -Path $Path -Contains $Contains -Line $Line -Include $Include -Exclude $Exclude -First $First" - $Path = Remove-Suffix -String $Path -Remove "\" - if (Test-Path $Path) - { - $Contains = $Contains.Trim() - $Count = 0 - $Files = Get-Childitem -Path $Path -Include $Include -Exclude $Exclude -Recurse -Force | select -First $First - ForEach ($File in $Files) - { - [Int32]$ContainsIndex = -1 - $Affected = 0 - $Content=Get-Content $File.PSPath - # Search for matches - For([Int32]$Count = 0; $Count -lt $Content.Length; $Count++) - { - $CurrentLine = $Content[$Count].Trim() - If(($ContainsIndex -eq -1) -and ($CurrentLine -eq $Contains)) - { - $ContainsIndex = $Count - Break - } - } - # Evaluate search - If($ContainsIndex -gt -1) - { - # Select before line, add -Line, select after line - $NewContent = (($Content | Select -First $ContainsIndex) + ($Line + [Environment]::NewLine) + ($Content | select -Last ($Content.Length - $ContainsIndex -1))) - } - else - { - # No Match Found - $NewContent = $Content - } - Set-Content $File.PSPath -Value $NewContent - $Affected = $Count - } - Write-Verbose "[Success] $Count items affected. $(Get-CurrentFile) at $(Get-CurrentLine)." - } - else - { - Write-Verbose "[OK] 0 items affected. $(Get-CurrentFile) at $(Get-CurrentLine)." - } -} -export-modulemember -function Update-LineByContains - -#----------------------------------------------------------------------- -# Update-ContentsByTag [-Path []] -# [-Open [] [-Close []] -# -# Example: .\Update-ContentsByTag -Path $Path -Include *.sln -Open "GlobalSection(TeamFoundationVersionControl) = preSolution" -Close "EndGlobalSection" -#----------------------------------------------------------------------- -function Update-ContentsByTag -{ - param ( - [Parameter(Mandatory=$true,ValueFromPipelineByPropertyName=$true)] - [string]$Path = $(throw '-Path is a required parameter.'), - [Parameter(Mandatory=$true,ValueFromPipelineByPropertyName=$true)] - [string]$Open = $(throw '-Open is a required parameter.'), - [Parameter(Mandatory=$true,ValueFromPipelineByPropertyName=$true)] - [string]$Close = $(throw '-Close is a required parameter.'), - [Parameter(Mandatory=$true,ValueFromPipelineByPropertyName=$true)] - [string]$Value = $(throw '-Value is a required parameter.'), - [string[]]$Include = "*.*", - [string[]]$Exclude = "", - [Int32]$First = 100 - ) - Write-Host "Update-ContentsByTag -Path $Path -Open $Open -Close $Close -Include $Include -Exclude $Exclude -First $First" - $Path = Remove-Suffix -String $Path -Remove "\" - [String]$PaddingLeft = ' ' - if (Test-Path $Path) - { - $Open = $Open.Trim() - $Close = $Close.Trim() - $Affected = 0 - $Files = Get-Childitem -Path $Path -Include $Include -Exclude $Exclude -Recurse -Force | select -First $First - ForEach ($File in $Files) - { - [Int32]$OpenIndex = -1 - [Int32]$CloseIndex = -1 - [String]$NewValue = "" - $Content=Get-Content $File.PSPath - # Search for matches - For([Int32]$Count = 0; $Count -lt $Content.Length; $Count++) - { - $CurrentLine = $Content[$Count].Trim() - If(($OpenIndex -eq -1) -and ($CurrentLine -like "*$Open*")) - { - $OpenIndex = $Count - } - If(($OpenIndex -gt -1) -and ($CurrentLine -like "*$Close*")) - { - $CloseIndex = $Count - Break - } - } - # Evaluate search - If(($OpenIndex -gt -1) -and ($OpenIndex -le $CloseIndex)) - { - if($OpenIndex -eq $CloseIndex) - { - # Open/Close on same line, rebuild the line with new contents - $NewValue = ($Open + $Value + $Close) - } - else - { - $NewValue = $Value - } - # Update content - $NewContent = ($Content | Select -First ($OpenIndex)) + ($PaddingLeft + $NewValue) + ($Content | select -Last ($Content.Length - $CloseIndex - 1)) - $Affected = 1 - } - else - { - # No Match Found - $NewContent = $Content - } - Set-Content $File.PSPath -Value $NewContent - } - Write-Verbose "[Success] $Affected items affected. $(Get-CurrentFile) at $(Get-CurrentLine)." - } - else - { - Write-Verbose "[OK] 0 items affected. $(Get-CurrentFile) at $(Get-CurrentLine)." - } -} -export-modulemember -function Update-ContentsByTag - -#----------------------------------------------------------------------- -# Update-Text [-Path []] -# [-Include [] [-Exclude []] -# -# Example: .\Update-Text -Path \\source\path -Include *.cs -Old "Use gotos" -New "Point at people who use gotos" -#----------------------------------------------------------------------- -function Update-Text -{ - param ( - [Parameter(Mandatory=$true,ValueFromPipelineByPropertyName=$true)] - [string]$Path = $(throw '-Path is a required parameter.'), - [Parameter(Mandatory=$true,ValueFromPipelineByPropertyName=$true)] - [string]$Old = $(throw '-Old is a required parameter.'), - [Parameter(Mandatory=$true,ValueFromPipelineByPropertyName=$true)] - [string]$New = $(throw '-New is a required parameter.'), - [Parameter(Mandatory=$true,ValueFromPipelineByPropertyName=$true)] - [string[]]$Include = $(throw '-Include is a required parameter.'), - [string[]]$Exclude = "", - [Int32]$First = 100 - ) - Write-Host "Update-Text -Path $Path -Old $Old -New $New -Include $Include -Exclude $Exclude -First $First" - $Path = Remove-Suffix -String $Path -Remove "\" - $Count = 0 - if (Test-Path $Path) - { - $ConfigFiles=Get-Childitem $Path -Include $Include -Exclude $Exclude -Recurse -Force | select -First $First - foreach ($Item in $ConfigFiles) - { - Set-ReadOnly -Path $Item.PSPath -ReadOnly $false - (Get-Content $Item.PSPath) | - Foreach-Object {$_.Replace($Old, $New) - } | - Set-Content $Item.PSPath -force - $Count = $Count + 1 - } - Write-Verbose "[Success] $Count items affected. $(Get-CurrentFile) at $(Get-CurrentLine)." - } - else - { - Write-Verbose "[OK] 0 items affected. $(Get-CurrentFile) at $(Get-CurrentLine)." - } -} -export-modulemember -function Update-Text - -#----------------------------------------------------------------------- -# Update-TextByContains [-Path []] -# [-Contains [] [-Close []] -# -# Example: .\Update-TextByContains -Path \\source\path -Include AssemblyInfo.cs -Contains 'AssemblyVersion(' -Line '[assembly: AssemblyVersion("5.20.07")]' -#----------------------------------------------------------------------- -function Update-TextByContains -{ - param ( - [string]$Path = $(throw '-Path is a required parameter.'), - [string]$Contains = $(throw '-Contains is a required parameter.'), - [string]$Old = $(throw '-Old is a required parameter.'), - [string]$New = $(throw '-New is a required parameter.'), - [string[]]$Include = "*.*", - [string[]]$Exclude = "", - [Int32]$First = 100 - ) - Write-Host "Update-TextByContains -Path $Path -Contains $Contains -Old $Old -New $New -Include $Include -Exclude $Exclude -First $First" - $Path = Remove-Suffix -String $Path -Remove "\" - if (Test-Path $Path) - { - $Contains = $Contains.Trim() - $Count = 0 - $Files = Get-Childitem -Path $Path -Include $Include -Exclude $Exclude -Recurse -Force | select -First $First - ForEach ($File in $Files) - { - [Int32]$FoundIndex = -1 - [String]$FoundLine = '' - $Affected = 0 - $Content=Get-Content $File.PSPath - # Search for matches - For([Int32]$Count = 0; $Count -lt $Content.Length; $Count++) - { - $CurrentLine = $Content[$Count].Trim() - If(($FoundIndex -eq -1) -and ($CurrentLine.ToLowerInvariant().Contains($Contains.ToLowerInvariant()))) - { - $FoundIndex = $Count - $FoundLine = $CurrentLine - Break - } - } - # Evaluate search - If($FoundIndex -gt -1) - { - # Replace text inside of line - $NewLine = $FoundLine.Replace($Old, $New) - # Select before line, add $NewLine, select after line - $NewContent = (($Content | Select -First $FoundIndex) + ($NewLine + [Environment]::NewLine) + ($Content | select -Last ($Content.Length - $FoundIndex -1))) - } - else - { - # No Match Found - $NewContent = $Content - } - Set-Content $File.PSPath -Value $NewContent - $Affected = $Count - } - Write-Verbose "[Success] $Count items affected. $(Get-CurrentFile) at $(Get-CurrentLine)." - } - else - { - Write-Verbose "[OK] 0 items affected. $(Get-CurrentFile) at $(Get-CurrentLine)." - } -} -export-modulemember -function Update-TextByContains - -#----------------------------------------------------------------------- -# Update-TextByTable [-Path []] [-Replace []] -# [-Include [] [-Exclude []] -# -# Example: .\Update-TextByTable -Path \\source\path -Include *.cs -# -Replace @{'Old1' = 'New1' -# 'Old2' = 'New2' -# 'Old3' = 'New3'} -#----------------------------------------------------------------------- -function Update-TextByTable -{ - param ( - [Parameter(Mandatory=$true,ValueFromPipelineByPropertyName=$true)] - [string]$Path = $(throw '-Path is a required parameter.'), - [Parameter(Mandatory=$true,ValueFromPipelineByPropertyName=$true)] - [hashtable]$Replace = $(throw '-Replace is a required parameter.'), - [Parameter(Mandatory=$true,ValueFromPipelineByPropertyName=$true)] - [string[]]$Include = $(throw '-Include is a required parameter.'), - [string[]]$Exclude = "", - [Int32]$First = 100 - ) - Write-Host "Update-Text -Path $Path -Old $Old -New $New -Include $Include -Exclude $Exclude -First $First" - $Path = Remove-Suffix -String $Path -Remove "\" - if (Test-Path $Path) - { - Write-Verbose "Get-Childitem $Path -Include $Include -Exclude $Exclude -Recurse -Force | select -First $First" - $ConfigFiles=Get-Childitem $Path -Include $Include -Exclude $Exclude -Recurse -Force | select -First $First - Write-Verbose "ConfigFiles: $ConfigFiles" - $Count = 0 - foreach ($Item in $ConfigFiles) - { - Write-Verbose "Get-Content $Item.PSPath" - $fileLines = Get-Content $Item.PSPath - Write-Verbose "fileLines: $fileLines" - if($fileLines) - { - foreach($replaceItem in $Replace.GetEnumerator()) { - Write-Verbose "$fileLines.Replace($replaceItem.Key, $replaceItem.Value)" - $fileLines = $fileLines.Replace($replaceItem.Key, $replaceItem.Value) - } - Write-Verbose "Set-Content -Path $Item.PSPath -Value $fileLines -force" - Set-Content -Path $Item.PSPath -Value $fileLines -force - } - $Count = $Count + 1 - } - Write-Verbose "[Success] $Count items affected. $(Get-CurrentFile) at $(Get-CurrentLine)." - } - else - { - Write-Verbose "[OK] 0 items affected. $(Get-CurrentFile) at $(Get-CurrentLine)." - } -} -export-modulemember -function Update-TextByTable \ No newline at end of file diff --git a/scripts/azure-resources/key-vault/Set-AzKeyVaultPolicy.ps1 b/scripts/azure-resources/key-vault/Set-AzKeyVaultPolicy.ps1 deleted file mode 100644 index bab3673..0000000 --- a/scripts/azure-resources/key-vault/Set-AzKeyVaultPolicy.ps1 +++ /dev/null @@ -1,43 +0,0 @@ -#----------------------------------------------------------------------- -# Set-AzKeyVaultPolicy [-Name []] [-ObjectId []] [-SecretPermissions []] -# -# Example: .\Set-AzKeyVaultPolicy -Name kv-PRODUCT-ENVIRONMENT-001 -ObjectId 00000000-0000-0000-0000-000000000000 -SecretPermissions list get -# CLI: -# az keyvault set-policy --name "" --spn --secret-permissions list get -# az keyvault update --name "" --resource-group "" --enabled-for-deployment "true" -#----------------------------------------------------------------------- - -# *** -# *** Parameters -# *** -param -( - [string] $Name=$(throw '-Name is a required parameter. (kv-PRODUCT-ENVIRONMENT-001)'), - [string] $ObjectId=$(throw '-ObjectId is a required parameter. (00000000-0000-0000-0000-000000000000)'), - [string] $SecretPermissions='list get' -) - -# *** -# *** Initialize -# *** -if ($IsWindows) { Set-ExecutionPolicy Unrestricted -Scope Process -Force } -$VerbosePreference = 'SilentlyContinue' #'Continue' -[String]$ThisScript = $MyInvocation.MyCommand.Path -[String]$ThisDir = Split-Path $ThisScript -[DateTime]$Now = Get-Date -Set-Location $ThisDir # Ensure our location is correct, so we can use relative paths -Write-Host "*****************************" -Write-Host "*** Starting: $ThisScript on $Now" -Write-Host "*****************************" -# Imports -Import-Module "./System.psm1" -Install-Module -Name Az.Accounts -AllowClobber -Scope CurrentUser -Install-Module -Name Az.Resources -AllowClobber -Scope CurrentUser - -# *** -# *** Auth -# *** -Write-Host "*** Auth ***" -Connect-AzAccount -Tenant $TenantId -Subscription $SubscriptionId - -Set-AzKeyVaultAccessPolicy -VaultName $Name -ObjectId $ObjectId -PermissionsToSecrets $SecretPermissions -EnabledForDeployment \ No newline at end of file From 75aff958f0ff0ae54c42b4dae137b8676b5a7063 Mon Sep 17 00:00:00 2001 From: Robert Good Date: Fri, 16 Oct 2026 11:33:15 -0700 Subject: [PATCH 3/4] readme and powershell modernize --- .github/CODEOWNERS | 1 + .github/copilot-instructions.md | 26 +++++ .github/dependabot.yml | 10 ++ .github/pull_request_template.md | 8 ++ .github/workflows/validate.yml | 32 ++++++ README.md | 46 +++++++- scripts/AzureCli.psm1 | 57 ++++++++++ .../Get-AzOrphanedResources.ps1 | 62 +++++++++++ scripts/azure-governance/README.md | 9 ++ .../azure-resources/Remove-LandingZone.ps1 | 2 +- .../azure-resources/Update-PowershellGet.ps1 | 2 +- .../azure-resources/azure-ad/Get-AzureAd.ps1 | 2 +- .../azure-ad/New-AzServicePrinciple.ps1 | 2 +- .../key-vault/Convert-AzKeyVaultToRbac.ps1 | 101 ++++++++++++++++++ .../logic-apps/Remove-LogicApp.ps1 | 2 +- .../azure-resources/sql/Remove-SQLServer.ps1 | 2 +- .../storage-account/Remove-StorageAccount.ps1 | 2 +- .../Get-AzAppCredentialExpiry.ps1 | 54 ++++++++++ .../Get-AzKeyVaultSecurityAudit.ps1 | 64 +++++++++++ scripts/azure-security/README.md | 11 ++ scripts/cybersecurity/Tls/Set-Tls.ps1 | 2 +- 21 files changed, 485 insertions(+), 12 deletions(-) create mode 100644 .github/CODEOWNERS create mode 100644 .github/copilot-instructions.md create mode 100644 .github/dependabot.yml create mode 100644 .github/pull_request_template.md create mode 100644 .github/workflows/validate.yml create mode 100644 scripts/AzureCli.psm1 create mode 100644 scripts/azure-governance/Get-AzOrphanedResources.ps1 create mode 100644 scripts/azure-governance/README.md create mode 100644 scripts/azure-resources/key-vault/Convert-AzKeyVaultToRbac.ps1 create mode 100644 scripts/azure-security/Get-AzAppCredentialExpiry.ps1 create mode 100644 scripts/azure-security/Get-AzKeyVaultSecurityAudit.ps1 create mode 100644 scripts/azure-security/README.md diff --git a/.github/CODEOWNERS b/.github/CODEOWNERS new file mode 100644 index 0000000..f5ae96f --- /dev/null +++ b/.github/CODEOWNERS @@ -0,0 +1 @@ +* @goodtocode diff --git a/.github/copilot-instructions.md b/.github/copilot-instructions.md new file mode 100644 index 0000000..c3b3489 --- /dev/null +++ b/.github/copilot-instructions.md @@ -0,0 +1,26 @@ +# Copilot instructions: cloud-admin + +This repo is a PowerShell and Markdown knowledge base for Azure cloud administration, engineering, and architecture (scripts, how-to docs, command references, T-SQL DBA scripts). + +## PowerShell scripts +- Target PowerShell 7+ on Windows; use Windows paths in docs, forward slashes in `Import-Module` relative paths. +- Start each script with the existing header comment: synopsis line, parameter list, and an `Example:` line. +- Use `param()` with typed parameters; `$ErrorActionPreference = 'Stop'` for new scripts. +- Anything that creates, changes, or deletes resources must use `[CmdletBinding(SupportsShouldProcess)]` and honor `-WhatIf`. +- Prefer `az` CLI or `Az.*` modules. Do not depend on `az` extensions. Check `$LASTEXITCODE` after `az` calls and keep stderr out of parsed JSON. +- Always wrap `ConvertFrom-Json` results that may be single items in `@()` before indexing or counting. +- Shared helpers: import from `scripts/System.psm1` and `scripts/Azure.psm1` only (never copy the module into subfolders). Compute the relative path from the script's own folder. +- Install modules only when missing (`Get-Module -ListAvailable`), not on every run. +- Make bulk operations resilient: skip and report items that fail or are missing, then print a summary. + +## Git workflow +- Do not run `git commit`, `git push`, or create pull requests. Leave changes uncommitted in the working tree so the repo owner can review them, then commit, push, and open the PR themselves. + +## Security +- Never commit secrets, keys, tokens, real tenant/subscription/object IDs, or customer data. Use `00000000-0000-0000-0000-000000000000` placeholders. +- Default to least privilege in examples; call out destructive commands clearly. + +## Documentation (docs/) +- Markdown how-tos use the naming pattern `How-to .md` and `Commands - .md`. +- Show runnable commands in fenced `powershell`/`bash` blocks; state prerequisites and required permissions. +- Update `README.md` when adding a notable script or doc. diff --git a/.github/dependabot.yml b/.github/dependabot.yml new file mode 100644 index 0000000..0359b44 --- /dev/null +++ b/.github/dependabot.yml @@ -0,0 +1,10 @@ +version: 2 +updates: + - package-ecosystem: "github-actions" + directory: "/" + schedule: + interval: "monthly" + assignees: + - "goodtocode" + reviewers: + - "goodtocode" diff --git a/.github/pull_request_template.md b/.github/pull_request_template.md new file mode 100644 index 0000000..b71f9c5 --- /dev/null +++ b/.github/pull_request_template.md @@ -0,0 +1,8 @@ +## Summary + + +## Checklist +- [ ] Script header/example updated; state-changing scripts support `-WhatIf` +- [ ] Tested against a non-production subscription/environment +- [ ] No secrets, real tenant/subscription/object IDs, or customer data +- [ ] README/docs updated if needed diff --git a/.github/workflows/validate.yml b/.github/workflows/validate.yml new file mode 100644 index 0000000..d497c79 --- /dev/null +++ b/.github/workflows/validate.yml @@ -0,0 +1,32 @@ +name: Validate + +on: + pull_request: + push: + branches: [main] + +permissions: + contents: read + +jobs: + powershell: + runs-on: windows-latest + steps: + - uses: actions/checkout@v4 + - name: Parse all PowerShell files + shell: pwsh + run: | + $failed = $false + Get-ChildItem -Recurse -Include *.ps1,*.psm1 -File | ForEach-Object { + $errors = $null + [void][System.Management.Automation.Language.Parser]::ParseFile($_.FullName, [ref]$null, [ref]$errors) + foreach ($e in $errors) { Write-Host "::error file=$($_.FullName),line=$($e.Extent.StartLineNumber)::$($e.Message)"; $failed = $true } + } + if ($failed) { exit 1 } + - name: PSScriptAnalyzer (errors only) + shell: pwsh + run: | + Install-Module PSScriptAnalyzer -Force -Scope CurrentUser + $r = Invoke-ScriptAnalyzer -Path . -Recurse -Severity Error + $r | Format-Table RuleName, ScriptName, Line, Message -AutoSize + if ($r) { exit 1 } diff --git a/README.md b/README.md index 52a8162..1cf0e81 100644 --- a/README.md +++ b/README.md @@ -12,8 +12,46 @@ A collection of PowerShell scripts, Azure/DevOps tooling, and SQL utilities for See [docs/How-to Setup - Dev Machine.md](docs/How-to%20Setup%20-%20Dev%20Machine.md) for the full manual walkthrough this script automates. ## Repository Structure -| Folder | Description | +Organized by intent: **know your estate** (governance), **reduce risk** (security), **change things safely** (resources), and **run the platform** (everything else). + +| Folder | Purpose | +|---|---| +| [docs/](docs) | How-to guides and command references (AD, SQL, SSL, web, build server, Azure CLI). | +| [scripts/azure-governance/](scripts/azure-governance) | Estate-wide inventory and FinOps hygiene via Azure Resource Graph (read-only). | +| [scripts/azure-security/](scripts/azure-security) | Posture and identity-hygiene reports: Key Vault audit, expiring app credentials (read-only). | +| [scripts/azure-resources/](scripts/azure-resources) | Create/change/remove Azure resources: Key Vault, storage, SQL, Front Door, Logic Apps, Entra, Monitor. | +| [scripts/azure-devops/](scripts/azure-devops) | Azure DevOps helpers (branch names, library variables, pull requests). | +| [scripts/azure-functions/](scripts/azure-functions) | Local Azure Functions host and certificate helpers. | +| [scripts/cybersecurity/](scripts/cybersecurity) | Tokens, certificates, cryptography, TLS readiness, PCI DSS tests, event logs. | +| [scripts/dev-experience/](scripts/dev-experience) | Developer machine bootstrap and terminal profile. | +| [scripts/dns/](scripts/dns), [scripts/iis-web-server/](scripts/iis-web-server), [scripts/windows-servers/](scripts/windows-servers) | Classic infrastructure and server administration. | +| [scripts/dotnet/](scripts/dotnet), [scripts/sitecore/](scripts/sitecore), [scripts/imperva/](scripts/imperva) | App-specific build, publish, and load-balancer tooling. | +| [t-sql/](t-sql) | SQL Server DBA scripts. | + +Shared modules: [scripts/AzureCli.psm1](scripts/AzureCli.psm1) (az CLI + Resource Graph helpers), [scripts/Azure.psm1](scripts/Azure.psm1), [scripts/System.psm1](scripts/System.psm1). + +## Modern Azure scripts (start here) +All read-only unless noted, `az` CLI only (no extensions), work across every subscription you can access, and export CSV with `-OutputPath`. + +| Script | Use it to | |---|---| -| [docs/](docs) | How-to guides and command references | -| [scripts/](scripts) | PowerShell scripts for Azure, DevOps, dev machine setup, and Windows servers | -| [t-sql/](t-sql) | SQL Server DBA scripts | \ No newline at end of file +| [Get-AzKeyVaultSecurityAudit.ps1](scripts/azure-security/Get-AzKeyVaultSecurityAudit.ps1) | Find vaults on legacy access policies, without purge protection, or open to the public internet. | +| [Get-AzAppCredentialExpiry.ps1](scripts/azure-security/Get-AzAppCredentialExpiry.ps1) | Prevent outages from expired Entra app secrets/certificates. | +| [Get-AzOrphanedResources.ps1](scripts/azure-governance/Get-AzOrphanedResources.ps1) | Find unattached disks, idle public IPs, orphaned NICs and other waste. | +| [Convert-AzKeyVaultToRbac.ps1](scripts/azure-resources/key-vault/Convert-AzKeyVaultToRbac.ps1) | **Changes state.** Migrate access-policy vaults to RBAC with equivalent built-in roles. Run with `-WhatIf` first. | + +```powershell +./scripts/azure-security/Get-AzKeyVaultSecurityAudit.ps1 -OutputPath ./kv-audit.csv +./scripts/azure-resources/key-vault/Convert-AzKeyVaultToRbac.ps1 -SubscriptionId "" -WhatIf +``` + +[Set-AzKeyVaultAclGroup.ps1](scripts/azure-resources/key-vault/Set-AzKeyVaultAclGroup.ps1) grants groups access-policy permissions on legacy vaults. Use it only as a short-term bridge (for example, data migrations) until vaults are moved to RBAC. + +## Modernization backlog +Older scripts predate current practice. When touching them, prefer: Microsoft Graph / `az ad` over the retired `AzureAD` module (for example [Add-ManagedIdentityRole.ps1](scripts/azure-resources/azure-ad/Add-ManagedIdentityRole.ps1)), `[Parameter(Mandatory)]` over `$(throw ...)` defaults, no `Set-ExecutionPolicy Unrestricted`, and `-WhatIf` on every destructive script. + +## Conventions +- Shared modules live only in [scripts/](scripts). Import them with `Join-Path $PSScriptRoot` (new scripts) or a relative path (older scripts). +- Scripts that change state support `-WhatIf` (`SupportsShouldProcess`). Run with `-WhatIf` first. +- No secrets, tenant/subscription IDs, or customer data in the repo; use placeholders (`00000000-...`). +- See [.github/copilot-instructions.md](.github/copilot-instructions.md) for full authoring guidance. \ No newline at end of file diff --git a/scripts/AzureCli.psm1 b/scripts/AzureCli.psm1 new file mode 100644 index 0000000..683a0a2 --- /dev/null +++ b/scripts/AzureCli.psm1 @@ -0,0 +1,57 @@ +#----------------------------------------------------------------------- +# Shared helpers for scripts that use the az CLI (no az extensions required). +# +# Import: Import-Module (Join-Path $PSScriptRoot '../AzureCli.psm1') -Force +#----------------------------------------------------------------------- + +function Invoke-Az { + # Runs az, returns stdout, throws stderr on failure (keeps warnings out of parsed JSON). + $errFile = New-TemporaryFile + try { + $out = & az @args 2>$errFile + if ($LASTEXITCODE -ne 0) { throw ((Get-Content $errFile -Raw) + ($out | Out-String)) } + $out + } finally { Remove-Item $errFile -ErrorAction SilentlyContinue } +} + +function Connect-AzCliIfNeeded { + # Logs in only when there is no active az session. Optional tenant. + param([string] $TenantId) + $null = & az account show 2>$null + if ($LASTEXITCODE -eq 0) { return } + if ($TenantId) { Invoke-Az login --tenant $TenantId --only-show-errors | Out-Null } + else { Invoke-Az login --only-show-errors | Out-Null } +} + +function Get-AzCliSubscription { + # Enabled subscriptions the signed-in user can see. Optional filter by id or name. + param([string[]] $Subscription) + $subs = @(Invoke-Az account list --query "[?state=='Enabled']" -o json | ConvertFrom-Json) + if ($Subscription) { $subs = @($subs | Where-Object { $_.id -in $Subscription -or $_.name -in $Subscription }) } + $subs +} + +function Invoke-AzResourceGraph { + # Runs an Azure Resource Graph (KQL) query across subscriptions through az rest, following paging. + param( + [Parameter(Mandatory)][string] $Query, + [string[]] $SubscriptionId + ) + if (-not $SubscriptionId) { $SubscriptionId = @(Get-AzCliSubscription).id } + $results = @() + $skipToken = $null + do { + $body = @{ query = $Query; subscriptions = @($SubscriptionId); options = @{ '$top' = 1000; resultFormat = 'objectArray' } } + if ($skipToken) { $body.options['$skipToken'] = $skipToken } + $tmp = New-TemporaryFile + try { + $body | ConvertTo-Json -Depth 6 | Set-Content -Path $tmp -Encoding utf8 + $resp = Invoke-Az rest --method post --url 'https://management.azure.com/providers/Microsoft.ResourceGraph/resources?api-version=2022-10-01' --body "@$($tmp.FullName)" -o json | ConvertFrom-Json + } finally { Remove-Item $tmp -ErrorAction SilentlyContinue } + if ($resp.data) { $results += @($resp.data) } + $skipToken = $resp.'$skipToken' + } while ($skipToken) + $results +} + +Export-ModuleMember -Function Invoke-Az, Connect-AzCliIfNeeded, Get-AzCliSubscription, Invoke-AzResourceGraph diff --git a/scripts/azure-governance/Get-AzOrphanedResources.ps1 b/scripts/azure-governance/Get-AzOrphanedResources.ps1 new file mode 100644 index 0000000..07330bc --- /dev/null +++ b/scripts/azure-governance/Get-AzOrphanedResources.ps1 @@ -0,0 +1,62 @@ +#----------------------------------------------------------------------- +# Get-AzOrphanedResources [-SubscriptionId ] [-SnapshotAgeDays ] [-OutputPath ] +# +# Read-only cost/hygiene report of orphaned Azure resources across subscriptions (Azure Resource Graph): +# unattached disks, unassociated public IPs, orphaned NICs, unused NSGs, empty App Service plans, old snapshots. +# Review before deleting; this script never deletes anything. +# +# Example: .\Get-AzOrphanedResources.ps1 +# Example: .\Get-AzOrphanedResources.ps1 -SubscriptionId aacn-devtest-200 -SnapshotAgeDays 60 -OutputPath .\orphans.csv +#----------------------------------------------------------------------- +[CmdletBinding()] +param +( + [string[]] $SubscriptionId, + [int] $SnapshotAgeDays = 90, + [string] $OutputPath +) + +$ErrorActionPreference = 'Stop' +Import-Module (Join-Path $PSScriptRoot '../AzureCli.psm1') -Force + +Connect-AzCliIfNeeded +$subs = @(Get-AzCliSubscription -Subscription $SubscriptionId) +if (-not $subs) { throw 'No matching enabled subscriptions.' } +$subName = @{}; $subs | ForEach-Object { $subName[$_.id] = $_.name } + +$query = @" +resources +| where (type =~ 'microsoft.compute/disks' and properties.diskState =~ 'Unattached' and isempty(managedBy)) + or (type =~ 'microsoft.network/publicipaddresses' and isnull(properties.ipConfiguration) and isnull(properties.natGateway)) + or (type =~ 'microsoft.network/networkinterfaces' and isnull(properties.virtualMachine) and isnull(properties.privateEndpoint)) + or (type =~ 'microsoft.network/networksecuritygroups' and isnull(properties.networkInterfaces) and isnull(properties.subnets)) + or (type =~ 'microsoft.web/serverfarms' and tolong(properties.numberOfSites) == 0) + or (type =~ 'microsoft.compute/snapshots' and todatetime(properties.timeCreated) < ago(${SnapshotAgeDays}d)) +| project name, type = tolower(type), resourceGroup, subscriptionId, location, sku = tostring(sku.name), id +"@ + +$labels = @{ + 'microsoft.compute/disks' = 'Unattached disk' + 'microsoft.network/publicipaddresses' = 'Unassociated public IP' + 'microsoft.network/networkinterfaces' = 'Orphaned NIC' + 'microsoft.network/networksecuritygroups' = 'Unused NSG' + 'microsoft.web/serverfarms' = 'Empty App Service plan' + 'microsoft.compute/snapshots' = "Snapshot older than $SnapshotAgeDays days" +} + +$report = @(Invoke-AzResourceGraph -Query $query -SubscriptionId $subs.id | ForEach-Object { + [pscustomobject]@{ + Subscription = $subName[$_.subscriptionId] + Category = $labels[$_.type] + Name = $_.name + ResourceGroup = $_.resourceGroup + Location = $_.location + Sku = $_.sku + ResourceId = $_.id + } +} | Sort-Object Category, Subscription, Name) + +$report | Format-Table Subscription, Category, Name, ResourceGroup, Sku -AutoSize +$report | Group-Object Category | Sort-Object Count -Descending | Format-Table Name, Count -AutoSize + +if ($OutputPath) { $report | Export-Csv -Path $OutputPath -NoTypeInformation; Write-Host "Saved: $OutputPath" } diff --git a/scripts/azure-governance/README.md b/scripts/azure-governance/README.md new file mode 100644 index 0000000..044cd76 --- /dev/null +++ b/scripts/azure-governance/README.md @@ -0,0 +1,9 @@ +# azure-governance + +**Purpose:** estate-wide visibility and cost hygiene (FinOps) using Azure Resource Graph. Scripts here report; they never delete. + +| Script | What it does | +|---|---| +| [Get-AzOrphanedResources.ps1](Get-AzOrphanedResources.ps1) | Finds unattached disks, unassociated public IPs, orphaned NICs, unused NSGs, empty App Service plans, and old snapshots across subscriptions. | + +Output can be exported with `-OutputPath` for review before any cleanup. diff --git a/scripts/azure-resources/Remove-LandingZone.ps1 b/scripts/azure-resources/Remove-LandingZone.ps1 index 47febeb..21a2675 100644 --- a/scripts/azure-resources/Remove-LandingZone.ps1 +++ b/scripts/azure-resources/Remove-LandingZone.ps1 @@ -30,7 +30,7 @@ Write-Host "*****************************" Write-Host "*** Starting: $ThisScript on $Now" Write-Host "*****************************" # Imports -Import-Module "./System.psm1" +Import-Module "../System.psm1" Install-Module -Name Az.Accounts -AllowClobber -Scope CurrentUser Install-Module -Name Az.Resources -AllowClobber -Scope CurrentUser diff --git a/scripts/azure-resources/Update-PowershellGet.ps1 b/scripts/azure-resources/Update-PowershellGet.ps1 index ec0a8c5..10d1304 100644 --- a/scripts/azure-resources/Update-PowershellGet.ps1 +++ b/scripts/azure-resources/Update-PowershellGet.ps1 @@ -27,7 +27,7 @@ Write-Host "*****************************" Write-Host "*** Starting: $ThisScript on $Now" Write-Host "*****************************" # Imports -Import-Module "./System.psm1" +Import-Module "../System.psm1" # *** # *** Execute diff --git a/scripts/azure-resources/azure-ad/Get-AzureAd.ps1 b/scripts/azure-resources/azure-ad/Get-AzureAd.ps1 index e255ba4..bfae464 100644 --- a/scripts/azure-resources/azure-ad/Get-AzureAd.ps1 +++ b/scripts/azure-resources/azure-ad/Get-AzureAd.ps1 @@ -26,7 +26,7 @@ Write-Host "*****************************" # *** Imports # *** Write-Host "*** Imports ***" -Import-Module "./System.psm1" +Import-Module "../../System.psm1" Install-Module -Name Az -AllowClobber -Scope CurrentUser # All Install-Module -Name AzureAD -AllowClobber -Scope CurrentUser #Install-Module -Name Az.Accounts -AllowClobber -Scope CurrentUser diff --git a/scripts/azure-resources/azure-ad/New-AzServicePrinciple.ps1 b/scripts/azure-resources/azure-ad/New-AzServicePrinciple.ps1 index 655fb54..f7fda95 100644 --- a/scripts/azure-resources/azure-ad/New-AzServicePrinciple.ps1 +++ b/scripts/azure-resources/azure-ad/New-AzServicePrinciple.ps1 @@ -29,7 +29,7 @@ Write-Host "*****************************" Write-Host "*** Starting: $ThisScript on $Now" Write-Host "*****************************" # Imports -Import-Module "./System.psm1" +Import-Module "../../System.psm1" Install-Module -Name Az.Accounts -AllowClobber -Scope CurrentUser Install-Module -Name Az.Resources -AllowClobber -Scope CurrentUser diff --git a/scripts/azure-resources/key-vault/Convert-AzKeyVaultToRbac.ps1 b/scripts/azure-resources/key-vault/Convert-AzKeyVaultToRbac.ps1 new file mode 100644 index 0000000..e8b7082 --- /dev/null +++ b/scripts/azure-resources/key-vault/Convert-AzKeyVaultToRbac.ps1 @@ -0,0 +1,101 @@ +#----------------------------------------------------------------------- +# Convert-AzKeyVaultToRbac [-SubscriptionId ] [-Name ] [-SwitchToRbac] [-WhatIf] +# +# Migrates legacy access-policy Key Vaults to Azure RBAC (the recommended model). +# For every access policy it creates equivalent built-in role assignments at the vault scope: +# keys: write/lifecycle -> Key Vault Crypto Officer | crypto ops -> Key Vault Crypto User | get/list -> Key Vault Reader +# secrets: write/lifecycle -> Key Vault Secrets Officer | get/list -> Key Vault Secrets User +# certificates: write/lifecycle -> Key Vault Certificates Officer | get/list -> Key Vault Reader +# all three at officer level -> Key Vault Administrator +# Role assignments are created first; the vault is only flipped to RBAC when -SwitchToRbac is supplied +# and every assignment for that vault succeeded. Managed-storage ("storage") permissions are not mapped. +# +# Requires Owner or User Access Administrator on the vaults. ALWAYS run with -WhatIf first. +# +# Example: .\Convert-AzKeyVaultToRbac.ps1 -WhatIf +# Example: .\Convert-AzKeyVaultToRbac.ps1 -SubscriptionId aacn-devtest-200 -Name kv-devtest-cert-001 -SwitchToRbac +#----------------------------------------------------------------------- +[CmdletBinding(SupportsShouldProcess)] +param +( + [string] $SubscriptionId, + [string[]] $Name, + [switch] $SwitchToRbac +) + +$ErrorActionPreference = 'Stop' +Import-Module (Join-Path $PSScriptRoot '../../AzureCli.psm1') -Force + +$keyWrite = 'create','update','import','delete','recover','backup','restore','purge','rotate','setrotationpolicy' +$keyCrypto = 'encrypt','decrypt','wrapkey','unwrapkey','sign','verify','release' +$secretWrite = 'set','delete','recover','backup','restore','purge' +$certWrite = 'create','update','import','delete','recover','backup','restore','purge','managecontacts','manageissuers','setissuers','deleteissuers' +$read = 'get','list' + +function Get-RolesForPolicy($permissions) { + $k = @($permissions.keys) | ForEach-Object { "$_".ToLower() } + $s = @($permissions.secrets) | ForEach-Object { "$_".ToLower() } + $c = @($permissions.certificates) | ForEach-Object { "$_".ToLower() } + $any = { param($have, $want) [bool]($have | Where-Object { $_ -in $want -or $_ -eq 'all' }) } + + $keyOfficer = & $any $k $keyWrite + $secOfficer = & $any $s $secretWrite + $certOfficer = & $any $c $certWrite + if ($keyOfficer -and $secOfficer -and $certOfficer) { return @('Key Vault Administrator') } + + $roles = @() + if ($keyOfficer) { $roles += 'Key Vault Crypto Officer' } + elseif (& $any $k $keyCrypto) { $roles += 'Key Vault Crypto User' } + elseif (& $any $k $read) { $roles += 'Key Vault Reader' } + if ($secOfficer) { $roles += 'Key Vault Secrets Officer' } + elseif (& $any $s $read) { $roles += 'Key Vault Secrets User' } + if ($certOfficer) { $roles += 'Key Vault Certificates Officer' } + elseif (& $any $c $read) { $roles += 'Key Vault Reader' } + $roles | Select-Object -Unique +} + +Connect-AzCliIfNeeded +if ($SubscriptionId) { Invoke-Az account set --subscription $SubscriptionId | Out-Null } +Write-Host "Subscription: $((Invoke-Az account show --query name -o tsv).Trim())" + +$vaults = @(Invoke-Az keyvault list --query '[].{name:name,rg:resourceGroup}' -o json | ConvertFrom-Json) +if ($Name) { + foreach ($m in ($Name | Where-Object { $_ -notin $vaults.name })) { Write-Warning "SKIP (not in this subscription): $m" } + $vaults = @($vaults | Where-Object { $_.name -in $Name }) +} + +$results = foreach ($v in $vaults) { + $vault = Invoke-Az keyvault show --name $v.name --resource-group $v.rg -o json | ConvertFrom-Json + if ($vault.properties.enableRbacAuthorization) { + [pscustomobject]@{ Vault = $v.name; ObjectId = '-'; Role = '-'; Status = 'Already RBAC' } + continue + } + + $failed = $false + $assigned = @(Invoke-Az role assignment list --scope $vault.id --query '[].{p:principalId,r:roleDefinitionName}' -o json | ConvertFrom-Json) + foreach ($policy in @($vault.properties.accessPolicies)) { + foreach ($role in @(Get-RolesForPolicy $policy.permissions)) { + $status = 'Created' + if ($assigned | Where-Object { $_.p -eq $policy.objectId -and $_.r -eq $role }) { $status = 'Exists' } + elseif ($PSCmdlet.ShouldProcess("$($v.name)", "Assign '$role' to $($policy.objectId)")) { + try { + Invoke-Az role assignment create --assignee-object-id $policy.objectId --role $role --scope $vault.id -o none | Out-Null + } catch { + if ($_.Exception.Message -match 'Cannot find user or service principal') { $status = 'Skipped (principal no longer exists)' } + else { $status = "FAILED: $($_.Exception.Message.Trim())"; $failed = $true } + } + } else { $status = 'WhatIf' } + [pscustomobject]@{ Vault = $v.name; ObjectId = $policy.objectId; Role = $role; Status = $status } + } + } + + if ($SwitchToRbac) { + if ($failed) { Write-Warning "Not switching $($v.name) to RBAC: some assignments failed." } + elseif ($PSCmdlet.ShouldProcess($v.name, 'Enable RBAC authorization')) { + Invoke-Az keyvault update --name $v.name --resource-group $v.rg --enable-rbac-authorization true -o none | Out-Null + [pscustomobject]@{ Vault = $v.name; ObjectId = '-'; Role = '-'; Status = 'Switched to RBAC' } + } + } +} + +$results | Format-Table -AutoSize diff --git a/scripts/azure-resources/logic-apps/Remove-LogicApp.ps1 b/scripts/azure-resources/logic-apps/Remove-LogicApp.ps1 index 852efd1..00dabbf 100644 --- a/scripts/azure-resources/logic-apps/Remove-LogicApp.ps1 +++ b/scripts/azure-resources/logic-apps/Remove-LogicApp.ps1 @@ -28,7 +28,7 @@ Write-Host "*****************************" Write-Host "*** Starting: $ThisScript on $Now" Write-Host "*****************************" # Imports -Import-Module "./System.psm1" +Import-Module "../../System.psm1" Install-Module -Name Az.Accounts -AllowClobber -Scope CurrentUser Install-Module -Name Az.LogicApp -AllowClobber -Scope CurrentUser diff --git a/scripts/azure-resources/sql/Remove-SQLServer.ps1 b/scripts/azure-resources/sql/Remove-SQLServer.ps1 index 224a0aa..659151a 100644 --- a/scripts/azure-resources/sql/Remove-SQLServer.ps1 +++ b/scripts/azure-resources/sql/Remove-SQLServer.ps1 @@ -28,7 +28,7 @@ Write-Host "*****************************" Write-Host "*** Starting: $ThisScript on $Now" Write-Host "*****************************" # Imports -Import-Module "./System.psm1" +Import-Module "../../System.psm1" Install-Module -Name Az.Accounts -AllowClobber -Scope CurrentUser Install-Module -Name Az.Sql -AllowClobber -Scope CurrentUser diff --git a/scripts/azure-resources/storage-account/Remove-StorageAccount.ps1 b/scripts/azure-resources/storage-account/Remove-StorageAccount.ps1 index 549a7c6..b9e1366 100644 --- a/scripts/azure-resources/storage-account/Remove-StorageAccount.ps1 +++ b/scripts/azure-resources/storage-account/Remove-StorageAccount.ps1 @@ -28,7 +28,7 @@ Write-Host "*****************************" Write-Host "*** Starting: $ThisScript on $Now" Write-Host "*****************************" # Imports -Import-Module "./System.psm1" +Import-Module "../../System.psm1" Install-Module -Name Az.Accounts -AllowClobber -Scope CurrentUser Install-Module -Name Az.Resources -AllowClobber -Scope CurrentUser Install-Module -Name Az.Storage -AllowClobber -Scope CurrentUser diff --git a/scripts/azure-security/Get-AzAppCredentialExpiry.ps1 b/scripts/azure-security/Get-AzAppCredentialExpiry.ps1 new file mode 100644 index 0000000..c539c10 --- /dev/null +++ b/scripts/azure-security/Get-AzAppCredentialExpiry.ps1 @@ -0,0 +1,54 @@ +#----------------------------------------------------------------------- +# Get-AzAppCredentialExpiry [-WithinDays ] [-IncludeServicePrincipals] [-ExcludeExpired] [-OutputPath ] +# +# Read-only report of Entra ID app registration secrets and certificates that are expired or +# expiring soon, to prevent credential-expiry outages. Prefer federated credentials / managed +# identities; use this to find what still depends on secrets. +# +# Requires: az login with permission to read applications (Application.Read.All or Directory Reader). +# +# Example: .\Get-AzAppCredentialExpiry.ps1 -WithinDays 60 +# Example: .\Get-AzAppCredentialExpiry.ps1 -WithinDays 30 -IncludeServicePrincipals -OutputPath .\expiring.csv +#----------------------------------------------------------------------- +[CmdletBinding()] +param +( + [int] $WithinDays = 60, + [switch] $IncludeServicePrincipals, + [switch] $ExcludeExpired, + [string] $OutputPath +) + +$ErrorActionPreference = 'Stop' +Import-Module (Join-Path $PSScriptRoot '../AzureCli.psm1') -Force +Connect-AzCliIfNeeded + +$now = Get-Date +$projection = '[].{name:displayName,appId:appId,secrets:passwordCredentials,certs:keyCredentials}' + +function ConvertTo-CredentialRow($items, $kind) { + foreach ($i in $items) { + foreach ($c in @($i.secrets)) { if ($c) { [pscustomobject]@{ Kind = $kind; Application = $i.name; AppId = $i.appId; Type = 'Secret'; Credential = $c.displayName; KeyId = $c.keyId; EndDate = [datetime]$c.endDateTime } } } + foreach ($c in @($i.certs)) { if ($c) { [pscustomobject]@{ Kind = $kind; Application = $i.name; AppId = $i.appId; Type = 'Certificate'; Credential = $c.displayName; KeyId = $c.keyId; EndDate = [datetime]$c.endDateTime } } } + } +} + +Write-Host 'Reading app registrations...' +$rows = @(ConvertTo-CredentialRow @(Invoke-Az ad app list --all --query $projection -o json | ConvertFrom-Json) 'AppRegistration') +if ($IncludeServicePrincipals) { + Write-Host 'Reading service principals...' + $rows += @(ConvertTo-CredentialRow @(Invoke-Az ad sp list --all --query $projection -o json | ConvertFrom-Json) 'ServicePrincipal') +} + +$report = $rows | ForEach-Object { + $days = [int][math]::Floor(($_.EndDate - $now).TotalDays) + $_ | Add-Member -NotePropertyName DaysRemaining -NotePropertyValue $days -PassThru | + Add-Member -NotePropertyName Status -NotePropertyValue $(if ($days -lt 0) { 'Expired' } else { 'Expiring' }) -PassThru +} | Where-Object { $_.DaysRemaining -le $WithinDays -and -not ($ExcludeExpired -and $_.Status -eq 'Expired') } | + Sort-Object DaysRemaining + +$report = @($report) +$report | Format-Table Kind, Application, Type, EndDate, DaysRemaining, Status -AutoSize +Write-Host "Expired: $(@($report | Where-Object Status -eq 'Expired').Count) | Expiring within $WithinDays days: $(@($report | Where-Object Status -eq 'Expiring').Count)" + +if ($OutputPath) { $report | Export-Csv -Path $OutputPath -NoTypeInformation; Write-Host "Saved: $OutputPath" } diff --git a/scripts/azure-security/Get-AzKeyVaultSecurityAudit.ps1 b/scripts/azure-security/Get-AzKeyVaultSecurityAudit.ps1 new file mode 100644 index 0000000..5516de0 --- /dev/null +++ b/scripts/azure-security/Get-AzKeyVaultSecurityAudit.ps1 @@ -0,0 +1,64 @@ +#----------------------------------------------------------------------- +# Get-AzKeyVaultSecurityAudit [-SubscriptionId ] [-OutputPath ] +# +# Read-only posture audit of every Key Vault across your subscriptions (one Azure Resource Graph query). +# Flags: legacy access-policy model, purge protection off, soft delete off, open public network access. +# +# Example: .\Get-AzKeyVaultSecurityAudit.ps1 +# Example: .\Get-AzKeyVaultSecurityAudit.ps1 -SubscriptionId aacn-devtest-200 -OutputPath .\kv-audit.csv +#----------------------------------------------------------------------- +[CmdletBinding()] +param +( + [string[]] $SubscriptionId, + [string] $OutputPath +) + +$ErrorActionPreference = 'Stop' +Import-Module (Join-Path $PSScriptRoot '../AzureCli.psm1') -Force + +Connect-AzCliIfNeeded +$subs = @(Get-AzCliSubscription -Subscription $SubscriptionId) +if (-not $subs) { throw 'No matching enabled subscriptions.' } + +$query = @' +resources +| where type =~ 'microsoft.keyvault/vaults' +| project name, resourceGroup, subscriptionId, location, + accessModel = iff(properties.enableRbacAuthorization == true, 'RBAC', 'AccessPolicy'), + softDelete = properties.enableSoftDelete, + purgeProtection = properties.enablePurgeProtection, + publicNetworkAccess = tostring(properties.publicNetworkAccess), + firewallDefault = tostring(properties.networkAcls.defaultAction), + privateEndpoints = array_length(properties.privateEndpointConnections) +'@ + +$subName = @{}; $subs | ForEach-Object { $subName[$_.id] = $_.name } +$vaults = @(Invoke-AzResourceGraph -Query $query -SubscriptionId $subs.id) + +$report = foreach ($v in $vaults) { + $findings = @() + if ($v.accessModel -eq 'AccessPolicy') { $findings += 'Legacy access policies (migrate to RBAC)' } + if (-not $v.purgeProtection) { $findings += 'Purge protection off' } + if ($v.softDelete -eq $false) { $findings += 'Soft delete off' } + if ($v.publicNetworkAccess -ne 'Disabled' -and $v.firewallDefault -ne 'Deny') { $findings += 'Open to public network' } + [pscustomobject]@{ + Subscription = $subName[$v.subscriptionId] + Vault = $v.name + ResourceGroup = $v.resourceGroup + AccessModel = $v.accessModel + PurgeProtection = [bool]$v.purgeProtection + PublicAccess = $v.publicNetworkAccess + FirewallDefault = $v.firewallDefault + PrivateEndpoints = [int]$v.privateEndpoints + FindingCount = $findings.Count + Findings = $findings -join '; ' + } +} + +$report = @($report | Sort-Object FindingCount -Descending) +$report | Format-Table Subscription, Vault, AccessModel, PurgeProtection, PublicAccess, FindingCount -AutoSize + +Write-Host "Vaults: $($report.Count) | Access policies: $(@($report | Where-Object AccessModel -eq 'AccessPolicy').Count) | No purge protection: $(@($report | Where-Object { -not $_.PurgeProtection }).Count) | Open to public: $(@($report | Where-Object Findings -like '*public network*').Count)" + +if ($OutputPath) { $report | Export-Csv -Path $OutputPath -NoTypeInformation; Write-Host "Saved: $OutputPath" } diff --git a/scripts/azure-security/README.md b/scripts/azure-security/README.md new file mode 100644 index 0000000..d1ad6d3 --- /dev/null +++ b/scripts/azure-security/README.md @@ -0,0 +1,11 @@ +# azure-security + +**Purpose:** read-only posture and identity-hygiene reporting across all subscriptions/tenant, so risks are found before they become incidents or outages. + +| Script | What it does | +|---|---| +| [Get-AzKeyVaultSecurityAudit.ps1](Get-AzKeyVaultSecurityAudit.ps1) | Audits every Key Vault: legacy access policies, purge protection, soft delete, public network exposure. | +| [Get-AzAppCredentialExpiry.ps1](Get-AzAppCredentialExpiry.ps1) | Lists expired/expiring Entra app registration (and optionally service principal) secrets and certificates. | + +All scripts are read-only, use the `az` CLI with no extensions, and can export to CSV with `-OutputPath`. +Related: [../azure-resources/key-vault/Convert-AzKeyVaultToRbac.ps1](../azure-resources/key-vault/Convert-AzKeyVaultToRbac.ps1) remediates the access-policy finding. diff --git a/scripts/cybersecurity/Tls/Set-Tls.ps1 b/scripts/cybersecurity/Tls/Set-Tls.ps1 index 17ccf29..6adc62c 100644 --- a/scripts/cybersecurity/Tls/Set-Tls.ps1 +++ b/scripts/cybersecurity/Tls/Set-Tls.ps1 @@ -27,7 +27,7 @@ Write-Host "*****************************" Write-Host "*** Starting: $ThisScript on $Now" Write-Host "*****************************" # Imports -Import-Module "./System.psm1" +Import-Module "../../System.psm1" # *** # *** Execute From cab625842dff4b5529d462d62b268c2c61e8123b Mon Sep 17 00:00:00 2001 From: Robert Good Date: Fri, 16 Oct 2026 11:57:07 -0700 Subject: [PATCH 4/4] best practices --- .vscode/settings.json | 3 +++ scripts/azure-functions/Certs/New-SelfSignedCert.ps1 | 4 ++-- scripts/cybersecurity/Certificates/Export-Certificate.ps1 | 4 ++-- scripts/cybersecurity/Certificates/Import-Certificate.ps1 | 4 ++-- scripts/cybersecurity/Certificates/New-SelfSignedCert.ps1 | 8 +++++++- scripts/cybersecurity/Identity/RunAs.ps1 | 4 +--- 6 files changed, 17 insertions(+), 10 deletions(-) create mode 100644 .vscode/settings.json diff --git a/.vscode/settings.json b/.vscode/settings.json new file mode 100644 index 0000000..5dabb89 --- /dev/null +++ b/.vscode/settings.json @@ -0,0 +1,3 @@ +{ + "sarif-viewer.connectToGithubCodeScanning": "off" +} \ No newline at end of file diff --git a/scripts/azure-functions/Certs/New-SelfSignedCert.ps1 b/scripts/azure-functions/Certs/New-SelfSignedCert.ps1 index e8692ad..94c223b 100644 --- a/scripts/azure-functions/Certs/New-SelfSignedCert.ps1 +++ b/scripts/azure-functions/Certs/New-SelfSignedCert.ps1 @@ -11,7 +11,7 @@ param ( [Parameter(Mandatory=$true,ValueFromPipelineByPropertyName=$true)] [string]$Path = $(throw '-Path is a required parameter.'), [Parameter(Mandatory=$true,ValueFromPipelineByPropertyName=$true)] - [string]$Password = $(throw '-Password is a required parameter.'), + [SecureString]$Password, [Parameter(Mandatory=$true,ValueFromPipelineByPropertyName=$true)] [string]$Dns = $(throw '-Dns is a required parameter.'), [string]$CertStoreLocation = 'cert:\LocalMachine\My' @@ -43,5 +43,5 @@ $thumbprint=$Certificate.Thumbprint Write-host "Created certificate with thumbprint $thumbprint" ## Export -$securePw = ConvertTo-SecureString -String $Password -Force –AsPlainText +$securePw = $Password Export-PfxCertificate -Cert "$CertStoreLocation\$thumbprint" -FilePath $Path -Password $securePw \ No newline at end of file diff --git a/scripts/cybersecurity/Certificates/Export-Certificate.ps1 b/scripts/cybersecurity/Certificates/Export-Certificate.ps1 index 593c3ee..b9174dc 100644 --- a/scripts/cybersecurity/Certificates/Export-Certificate.ps1 +++ b/scripts/cybersecurity/Certificates/Export-Certificate.ps1 @@ -11,7 +11,7 @@ param ( [Parameter(Mandatory=$true,ValueFromPipelineByPropertyName=$true)] [string]$Path = $(throw '-Path is a required parameter.'), [Parameter(Mandatory=$true,ValueFromPipelineByPropertyName=$true)] - [string]$Password = $(throw '-Password is a required parameter.'), + [SecureString]$Password, [Parameter(Mandatory=$true,ValueFromPipelineByPropertyName=$true)] [string]$Dns = $(throw '-Dns is a required parameter.'), [string]$CertStoreLocation = 'cert:\LocalMachine\My' @@ -38,7 +38,7 @@ if($foundCert.Thumbprint.Length -gt 0) $thumbprint=$foundCert.Thumbprint Write-host "Found cert matching $CertStoreLocation CN=$Dns Thumbprint=$thumbprint" ## Export - $securePw = ConvertTo-SecureString -String $Password -Force –AsPlainText + $securePw = $Password Export-PfxCertificate -Cert "$CertStoreLocation\$thumbprint" -FilePath $Path -Password $securePw } else { diff --git a/scripts/cybersecurity/Certificates/Import-Certificate.ps1 b/scripts/cybersecurity/Certificates/Import-Certificate.ps1 index 9d628da..f70fa2f 100644 --- a/scripts/cybersecurity/Certificates/Import-Certificate.ps1 +++ b/scripts/cybersecurity/Certificates/Import-Certificate.ps1 @@ -11,7 +11,7 @@ param ( [Parameter(Mandatory=$true,ValueFromPipelineByPropertyName=$true)] [string]$Path = $(throw '-Path is a required parameter.'), [Parameter(Mandatory=$true,ValueFromPipelineByPropertyName=$true)] - [string]$Password = $(throw '-Password is a required parameter.'), + [SecureString]$Password, [string]$CertStoreLocation = 'cert:\LocalMachine\My' ) #################################################################################### @@ -29,5 +29,5 @@ Write-Host "*****************************" Write-Host "*** Starting: $ThisScript On: $(Get-Date)" Write-Host "*****************************" #################################################################################### -$mypwd = ConvertTo-SecureString -String $Password -AsPlainText -Force +$mypwd = $Password Import-PfxCertificate -FilePath $Path -CertStoreLocation $CertStoreLocation -Password $mypwd \ No newline at end of file diff --git a/scripts/cybersecurity/Certificates/New-SelfSignedCert.ps1 b/scripts/cybersecurity/Certificates/New-SelfSignedCert.ps1 index 9eed904..6dc2e9c 100644 --- a/scripts/cybersecurity/Certificates/New-SelfSignedCert.ps1 +++ b/scripts/cybersecurity/Certificates/New-SelfSignedCert.ps1 @@ -19,9 +19,15 @@ param ( [string]$CertStoreLocation = 'Cert:\LocalMachine\My', [int]$ExpirationMonths = 24, [int]$KeyLength = 2048, - [SecureString]$Password = (ConvertTo-SecureString -String (New-Guid).ToString() -Force -AsPlainText) + [SecureString]$Password ) +if (-not $Password) { + # Random throwaway password generated without plain-text conversion + $Password = New-Object System.Security.SecureString + [char[]](New-Guid).ToString() | ForEach-Object { $Password.AppendChar($_) } +} + #################################################################################### Set-ExecutionPolicy Unrestricted -Scope Process -Force $VerbosePreference = 'SilentlyContinue' # 'SilentlyContinue' # 'Continue' diff --git a/scripts/cybersecurity/Identity/RunAs.ps1 b/scripts/cybersecurity/Identity/RunAs.ps1 index aede6fe..f589252 100644 --- a/scripts/cybersecurity/Identity/RunAs.ps1 +++ b/scripts/cybersecurity/Identity/RunAs.ps1 @@ -1,5 +1,3 @@ -$Username = "USER" -$UserPassword = ConvertTo-SecureString "PASSWORD" -AsPlainText -Force -$Credential = New-Object System.Management.Automation.PSCredential $Username, $UserPassword +$Credential = Get-Credential -Message "Enter the account to run as" $PSCommand = "" Start-Process powershell.exe -Credential $Credential -ArgumentList "-NoExit", "-Command $PSCommand" \ No newline at end of file