PowerShell utilities for enterprise automation, secure logging, identity validation, and cross-platform operational tooling.
IT-ToolBox is a practical PowerShell module for real-world admin and infrastructure workflows. It is designed for teams that want explicit validation, secure defaults, and portable behavior without hidden magic or fragile assumptions.
Operational work is full of small but expensive failures: invalid input, inconsistent logging, brittle naming rules, and fragile automation built on assumptions. IT-ToolBox was created to reduce those failure points with reusable PowerShell utilities that prioritize safety, clarity, and portability across modern enterprise environments.
This project packages automation patterns that are often built ad hoc in enterprise workplaces: filesystem validation, identity and DNS checks, log management, secure string handling, and operational diagnostics. The result is a reusable toolkit that prioritizes clarity, safety, and portability instead of one-off script logic.
- Cross-platform PowerShell 7.4+ design
- Secure logging and string-handling helpers with explicit safety boundaries
- Validation-first utilities for email, URLs, DNS, DN and UPN checks
- Operational helpers for timing, script context and filesystem hygiene
- Modernization work that preserves compatibility where it matters
- Built for real deployment scenarios, not just demo scripts
IT-ToolBox is designed for the kinds of tasks that recur in real administrative and operations work: validating names and input, writing safe logs, enforcing naming rules, tracing script context, and handling sensitive values without obscuring the logic behind complex utility wrappers.
Typical scenarios include:
- validating user and endpoint input in scripts before commands run
- adding consistent, redactable logging to automation workflows
- generating secure random values and supporting password workflows
- checking script paths and operational timing in automation tooling
- normalizing filesystem names and reducing operational errors before actions execute
The module emphasizes four things: explicit validation, safe defaults, cross-platform compatibility, and operational clarity. The goal is not to hide behavior behind clever abstractions, but to provide reliable building blocks that are easy to reason about, review, and adapt in production automation.
| Area | Examples |
|---|---|
| Logging and operations | New-LogEntry, New-Timer, Get-ElapsedTime, Stop-Timer |
| Validation | Test-IsEmail, Test-IsUrl, Test-IsValidDn, Test-IsValidUpn |
| Identity and AD helpers | Get-ReportChain, Convert-LogonTimestamp, Test-RegistryValue |
| Security and data handling | New-StringEncryption, New-StringDecryption, New-PhoneticPassword, Get-StringHashCode |
This repository is currently an active modernization preview. The codebase is intended for practical use, but the project is still evolving and compatibility expectations should be reviewed before adopting it broadly in production automation.
Current roadmap focus:
- preserve the modern PowerShell 7.4+ compatibility baseline
- keep validation behavior explicit and predictable
- improve operational safety and logging semantics
- maintain a clean migration path from legacy patterns
- document integration boundaries and supported dependencies clearly
This is the 3.0.0-beta1 modernization preview. The modernization review is complete; live AD, remote CIM and service authentication remain unverified. Requires PowerShell 7.4 or later (Core edition). Windows PowerShell 5.1 is not supported.
The module imports without WinSCP, GnuPG, Active Directory or Exchange
dependencies. Most utilities run on Windows, Linux and macOS.
Test-RegistryValue is Windows-only; remote Get-OsUpTime requires Windows CIM
cmdlets and a reachable Windows endpoint. Get-ReportChain requires an available
Get-ADUser command and access to AD when invoked. Clipboard output requires a
working platform clipboard backend.
Clone the repository with Git; no ZIP or build step is required:
git clone https://github.com/PsCustomObject/IT-ToolBox.git
cd IT-ToolBox
pwshThen run these commands in PowerShell from the repository root:
Import-Module ./IT-ToolBox.psd1 -ErrorAction Stop
Get-Command -Module IT-ToolBox
Get-Help New-LogEntry -Full
Test-IsEmail 'person@example.com'
New-PhoneticPassword -PasswordLength 16 -NoPasswordSpellThis imports the local manifest; it does not install the module globally. Import it
again in each new PowerShell session, using an absolute path when running elsewhere.
The master branch contains ongoing preview development. Record the commit used by
your automation with git rev-parse HEAD; updating your clone can change behavior.
To update an existing clone, first commit or otherwise preserve local changes, then:
git switch master
git pull --ff-onlyReload the updated module in PowerShell with
Import-Module ./IT-ToolBox.psd1 -Force -ErrorAction Stop.
For compatibility details, see migration from v2, the command sections below and integration ownership. For development, see CONTRIBUTING.md.
New-LogEntry, New-Timer, Get-TimerStatus, Stop-Timer, Get-ElapsedTime,
Get-ScriptDirectory, Get-ScriptName
Test-FileName, Test-IsValidPath, Test-IsIP, Test-IsDate, Test-IsEmail,
Test-IsUrl, Test-IsValidDn, Test-IsValidUpn, Get-ReportChain
New-StringEncryption, New-StringDecryption, New-RandomString,
New-RandomPassword, New-PhoneticPassword, New-ApiRequest,
New-StringConversion, Get-StringCheckSum, Get-StringHashCode
Convert-LogonTimestamp, Get-OsUpTime, Remove-SpecialCharacters,
Test-RegistryValue
Import-Module ./IT-ToolBox.psd1
New-LogEntry -LogMessage 'Started' -LogFilePath './automation.log' -NoConsole
$timer = New-Timer
Get-ElapsedTime -ElapsedTime $timer
Stop-Timer -Timer $timer# Validate input before use
if (-not (Test-IsEmail 'person@example.com')) {
throw 'The supplied address is invalid.'
}
# Add secure, redactable logging
New-LogEntry -LogMessage 'Processing request' -LogFilePath './automation.log' -Level WARNING
# Create a phonetic password with explicit composition rules
New-PhoneticPassword -PasswordLength 18 -NoPasswordSpellLogging output only enters the success pipeline when requested with -PassThru.
Use New-LogEntry -GetBuffer, -FlushBuffer and -ClearBuffer rather than accessing
module variables. A successful flush removes only the written entries; a failed file write
retains the buffer for retry. Buffer operations are serialized during a flush.
A partially completed filesystem write may still leave content on disk, so retrying after
an I/O failure does not provide an exactly-once delivery guarantee.
Without -LogFilePath, logs are created beside the calling script, or in the current
directory for interactive calls. Specify a path to select a stable log filename.
-RedactionText is literal text, including dollar signs. Specify only one buffered
severity switch, or use -BufferOnly -Level WARNING / ERROR.
Redaction is opt-in and does not guarantee detection of every secret.
- SCP and GnuPG wrappers and bundled WinSCP binaries are removed. Separate modules will own file transfer and OpenPGP; no replacement is bundled here.
Legacy/retains only the historical string encryption/decryption pair for migration of existing ciphertext in a separate session.- All commands formerly retained in
Staging/v3/now have supported implementations. Its README records the migration. Exchange/AzureAD session wrappers and the global certificate-validation bypass have been removed; their source remains in Git history. - Only the twenty-nine listed commands are exported. Private helpers, variables and aliases are not exported. Do not treat v3 as a drop-in replacement for every v2 script: removed commands and documented parameter, output and encryption changes require migration. No restoration of removed service wrappers is promised.
- The module GUID and Git history are preserved.
For a clean installable preview archive, run ./scripts/Build-Module.ps1 in
PowerShell after running the tests. The archive includes supported module code
and documentation, excluding Legacy, Staging and development files. See
build and installation instructions. Nothing is published
or installed automatically.
Install-Module Pester -RequiredVersion 5.7.1 -Scope CurrentUser
Invoke-Pester ./TestsCI runs syntax validation, isolated import and Pester on Windows, Linux and macOS using each hosted runner's installed PowerShell. It does not test every PowerShell release. Logger tests exercise module import, redaction, failed-write retention, default paths and simultaneous direct/buffered file writes from three processes. Temporary HKCU registry tests run on Windows and are skipped on Linux/macOS. Live AD, remote CIM and service authentication have not been integration-tested.
The logger is adopted from PowerShell-Functions/New-LogEntry at commit d5a9edd.
The integrated logger includes the maintenance fixes described in CHANGELOG.md.
See CHANGELOG.md for history. Released under the MIT License.
Filename and path checks are lexical checks, not guarantees of existence, permissions
or filesystem limits. Filename rules default to the host platform; use
-WindowsCompatible to validate Windows names on another platform. Path checks do
not validate each component as a filename.
Test-IsIP retains its historical command name; Test-IsIpAddress.ps1 is the source
filename. IPv4 shorthand accepted by .NET is deliberately rejected.
Test-IsDate defaults to the current culture. For deterministic input, use
Test-IsDate '2026-10-04' -Format 'yyyy-MM-dd' -Culture '' (invariant culture).
Test-IsEmail validates a practical subset of bare mailbox syntax: ASCII dot-atom
local parts (including plus tags) and DNS domains, including IDNs and single-label
names. Limits are 64 characters for the local part, 63 ASCII characters per domain
label and 254 characters for the address after IDN conversion. It intentionally
rejects display names, comments, quoted or Unicode local parts, address literals,
whitespace and controls. It is not a complete RFC email validator and does not
check mailbox existence, DNS or deliverability. The Email, Mail and Address
parameter aliases remain available.
Test-IsUrl accepts absolute HTTP, HTTPS, FTP and FTPS URLs with DNS/IDN hosts,
localhost, strict dotted IPv4 or bracketed IPv6, optional numeric ports 0–65535,
paths, queries and fragments. DNS root dots are allowed. It rejects credentials,
relative URLs, other schemes, raw whitespace/controls, backslashes, malformed
percent escapes, empty/invalid ports, IPv4 shorthand and IPv6 scope identifiers.
It checks syntax only, not endpoint reachability or whether fetching a URL is safe.
'person+tag@example.com', 'bad' | Test-IsEmail
'https://example.com:8443/api?name=value', '/relative' | Test-IsUrlBoth commands return one boolean per pipeline input; explicitly supplied null, empty or malformed input returns false. Migration from the staged versions: email validation no longer accepts a display-name/comment wrapper, and the URL regex is replaced with structured parsing and host checks. FTP and FTPS remain supported for compatibility; this does not introduce a file-transfer command.
The modern commands retain their names but intentionally change the encryption
format and require an explicit passphrase. They use .NET AES-256-GCM, random
16-byte salt and 12-byte nonce, a 16-byte authentication tag, and PBKDF2-HMAC-SHA256
with 600,000 iterations. Wrong passphrases and changed payloads throw; unauthenticated
plaintext is never returned. The ITTB1. prefix identifies this fixed format.
# $passphrase must come from your application's secret-handling mechanism.
$encrypted = New-StringEncryption -StringToEncrypt 'example' -EncryptPassPhrase $passphrase
$original = New-StringDecryption -EncryptedString $encrypted -EncryptPassPhrase $passphraseLimits: 1 MiB of plaintext UTF-8 and 4,096 passphrase characters. Encryption clears temporary plaintext and key byte arrays. Managed strings (including the passphrase, input plaintext and returned plaintext) cannot be reliably erased; this API is not a secret vault or password-storage API. Strong passphrases remain necessary. The functions perform string encryption only, not file encryption or OpenPGP.
New ciphertext is incompatible with the historical v2 string encryption format.
There is no automatic fallback. The original functions remain in Legacy/ solely
for decoding existing data in a separate session. Recover old plaintext with the
original passphrase, salt and vector, then encrypt it using the modern function.
If the old call used computer-name defaults, that original machine name is needed.
Legacy ciphertext lacks authentication, so successful decryption does not establish
its integrity. Do not overwrite existing encrypted data before verifying migration.
Caller-selected EncryptSalt and IntersectingVector parameters are removed;
new salts/nonces are generated automatically.
Implementation references: .NET AES-GCM, OWASP cryptographic storage and PBKDF2 work-factor guidance. The PBKDF2 work factor is adopted from OWASP guidance; it is not a security audit or a guarantee that every deployment meets a compliance standard.
New-PhoneticPassword retains its 12-character default, phonetic character table,
category-count parameters, aliases, color/display switches, clipboard option and
string return value. The original symbol exclusions and phonetic spellings are
unchanged. Numeric pipeline inputs accumulate into one returned password, as before.
New-PhoneticPassword -LowerCaseLetters 6 -CapitalCaseLetters 4 -NumberDigits 4 -Symbol 4
New-PhoneticPassword -PasswordLength 20 -NoPasswordSpell
New-PhoneticPassword -PasswordToClipboard -NoPasswordSpellCharacters are selected using .NET RandomNumberGenerator.GetInt32; composition
mode uses a Fisher-Yates shuffle. Clipboard writes use Set-Clipboard and honor
-WhatIf/-Confirm; an available platform clipboard backend is required. An
explicit clipboard failure throws rather than claiming a successful copy. CI mocks
clipboard writes and does not verify a desktop clipboard backend.
New-RandomString retains its alphabet and default length 12. New-RandomPassword
retains its alphabet and default length 8. Its historical -Complex switch remains
accepted with the same behavior; exact category guarantees are provided by
New-PhoneticPassword. Defaults are preserved for compatibility, not recommended
as universal password policies.
Lengths must be 1–4,096; composition counts must be nonnegative and total 1–4,096 per pipeline input. Independent secure selection allows repeated characters, fixing the old random-password length cap caused by sampling without replacement.
New-ApiRequest constructs a client request with client_id, grant_type and
optional client_secret, and returns the endpoint response. It is not a general
REST client or an automatic token-acquisition/refresh workflow.
$response = New-ApiRequest -ApiKey 'client-id' -ApiSecret $secret -ApiUrl 'https://example.invalid/oauth/token'
$response = New-ApiRequest -ApiKey 'client-id' -ApiSecret $secret -ApiUrl 'https://example.invalid/token' -ContentType 'application/json' -Headers @{ 'X-Request-ID' = 'request-id' }The default is POST with application/x-www-form-urlencoded. JSON content type
serializes the same authentication fields as JSON. Headers must be an IDictionary
(e.g. a hashtable); specify Content-Type with -ContentType, not inside Headers.
Only form and JSON bodies are supported.
Migration changes: GET no longer defaults, and a GET request cannot include
ApiSecret. Secret-free GET remains available and delegates dictionary query
encoding to Invoke-RestMethod. Requests with a client secret or Authorization
header require HTTPS. Other custom headers are not inspected for secrets; callers
should use HTTPS for sensitive requests. Automatic redirects are disabled; use
the final endpoint explicitly. URLs must be absolute HTTP(S) without user-info.
Connection timeout defaults to 30 seconds and can be configured with
-ConnectionTimeoutSeconds (alias -TimeoutSec). This is not a guaranteed total
wall-clock deadline. Failures terminate with the original Invoke-RestMethod error;
no retries or custom logging are added. Tests mock all HTTP calls: real endpoint
behavior and TLS are not integration-tested.
New-StringConversion retains the original character map, custom-map parameter,
unknown-character replacement and space options. Its default now matches the
documented behavior: spaces become hyphens. It returns exactly one string rather
than leaking collection indices. The map remains domain-specific (for example,
& maps to e); it is not a general-purpose transliteration or safe-path generator.
Custom maps replace the default map and are copied internally. Space policy overrides an existing space mapping without mutating the caller's table. Conversion normalizes text to Form C and handles unsupported Unicode text elements once, including supplementary characters. This changes output for decomposed accents and surrogate pairs compared with the old UTF-16 character loop.
Get-StringCheckSum retains uppercase hyphen-separated MD5 output by default for
existing non-security comparisons. Select -Algorithm SHA256, SHA384 or SHA512
when needed. MD5 is unsuitable for adversarial integrity checks.
Get-StringHashCode returns 64 uppercase SHA-256 hexadecimal characters by default.
Use -LegacyFormat only when comparing with old delimiter-free decimal output.
The hash algorithm remains SHA-256; the default representation intentionally changes.
Both hash commands use UTF-8 without a BOM and do not normalize text. Neither is
a password-storage function or an authentication mechanism.
Convert-LogonTimestamp accepts an unsigned decimal FILETIME string or Int64 value
and supports pipeline input. Local DateTime output remains the default; use -Utc
for UTC. -StringOutput defaults to yyyy-MM-dd, and -DateFormat also selects
string output. String formatting uses invariant culture. Invalid values throw.
Zero means no recorded logon and produces no output rather than a date in 1601.
The command converts a supplied value only: AD's replicated lastLogonTimestamp
is not an exact record of the user's latest authentication.
Convert-LogonTimestamp -TimeStamp $user.lastLogonTimestamp -Utc
Convert-LogonTimestamp -TimeStamp $user.lastLogonTimestamp -Utc -DateFormat 'yyyy-MM-dd HH:mm:ss'
Get-OsUpTime -FullOutput
Get-OsUpTime -ComputerName 'server01' -Credential $credential -FullOutputGet-OsUpTime preserves whole elapsed days as Int32 by default and TimeSpan with
-FullOutput. Local uptime delegates to PowerShell's built-in Get-Uptime on
Windows, Linux and macOS. Remote uptime requires Windows CIM cmdlets and a
reachable Windows CIM endpoint; no remote Linux/macOS support is implied.
Remote queries replace removed Get-WmiObject calls with Get-CimInstance.
They compute uptime from the server's LocalDateTime and LastBootUpTime, not
the client's clock. With -Credential, a temporary CIM session is created and
cleanup is attempted in finally. The historical -Credentials switch prompts
with Get-Credential; either credential option requires -ComputerName. Errors
terminate rather than returning warnings and no value. A failed cleanup is reported
without replacing an already-failed query's error. The caller's error preference
is not changed.
Tests cover actual local uptime and mocked remote query/session behavior. Remote Windows connectivity and authentication have not been integration-tested.
Remove-SpecialCharacters scans descendant files and directories, including hidden
items, and replaces the original punctuation list with a hyphen. Spaces and Unicode
are preserved. Despite its name, it operates on filesystem names, not input strings,
and its policy is not universal filename validation. The root is never renamed.
# Preview first; records include Path, NewName, DestinationPath, HasCollision and Status.
Remove-SpecialCharacters -ItemsPath './files'
Remove-SpecialCharacters -ItemsPath './files' -AutoFix -WhatIf
Remove-SpecialCharacters -ItemsPath './files' -AutoFixPreview is the default and creates no files unless logging is requested. AutoFix preflights existing destinations and duplicate proposed names before any rename, then processes deepest items first. Collision checks are conservatively insensitive to case on Windows and macOS, and case-sensitive on Linux. Links and junctions are not renamed or followed. Literal paths prevent wildcard expansion. Rename errors terminate; this is not a transaction and an I/O failure can leave earlier renames completed. Reported paths describe individual operations before ancestor renames. Avoid changing the tree concurrently with this command.
The historical -LogActivites spelling remains supported, with -LogActivities as
an alias. An optional -LogFilePath overrides the default activity log inside the
root directory. Log paths that participate in the rename plan or lie inside a
directory being renamed are rejected before writes. Only affected-item records
are logged; WhatIf suppresses logging.
This replaces the staged implementation's silent default output, fixed C:\Temp
logging and swallowed errors.
Test-RegistryValue -Path 'HKCU:\Software\Example' -Value 'Enabled' is Windows-only.
It checks literal value names, case-insensitively, and returns true for existing
empty strings or zero data. Use -Value '' for an unnamed/default value. Missing
keys or values return false; permission failures and other operational errors
terminate. Non-Registry provider paths are rejected. This does not inspect remote
registries or select an alternate registry view.
Filesystem tests use real temporary trees. Windows CI additionally exercises real temporary HKCU keys; those registry integration tests are skipped on Linux/macOS.
Test-IsValidDn checks a documented practical DN syntax, with escaped separators,
hex escapes, descriptor/OID attribute types and multi-valued RDNs. It accepts
non-DC-rooted names and does not restrict attributes to CN/OU/DC. It rejects empty
names/values, literal controls, invalid/dangling escapes, unescaped leading/trailing
value spaces and legacy quoted values. Hex-string notation is checked without BER
validation; decoded escape bytes are not checked for UTF-8 validity. This is not a
complete RFC parser, a canonical comparison or a schema/existence check.
Test-IsValidUpn uses a practical ASCII username policy: letters/digits at the
edges, with dots, underscores, hyphens and apostrophes internally, excluding
consecutive dots. The suffix supports DNS/IDN names, long suffixes and single-label
names. This is not email validation or a complete AD/Entra account-creation policy;
it does not check account existence or whether a suffix is configured.
Both validators preserve their parameter aliases, support pipeline input and return false for explicit null, empty or unsupported input. These policies replace the old DN regex and email-derived UPN regex; previously accepted/rejected inputs can change as described above.
Test-IsValidDn -DN 'CN=Last\, First,OU=People,DC=example,DC=com'
Test-IsValidUpn -UPN 'first.last@example.technology'
Get-ReportChain -SAM 'manager01' -DomainController 'dc01' -Properties SamAccountName,MailGet-ReportChain retains SAM, UPN and DN identity parameter sets and aliases,
DomainController, and ordered property selection. Its default properties remain
SamAccountName, UserPrincipalName, Mail, Manager and DirectReports; -Properties '*'
requests and projects all properties. It resolves exactly one manager, then uses
AD's matching-rule-in-chain filter to retrieve direct and transitive reports,
excluding the manager itself. Result order is the directory's order.
UPN lookup uses an escaped LDAP equality assertion rather than interpolated PowerShell filter expressions. Manager DN assertion values are escaped separately from DN string escaping, including UTF-8 bytes. Server and terminating error behavior are applied to both queries. Missing/ambiguous managers and AD failures throw rather than returning a warning and undefined results. The caller's error preference is not changed.
No ActiveDirectory dependency is required to import IT-ToolBox or use the naming validators. Get-ReportChain requires an available Get-ADUser command and access to an AD endpoint when invoked; it uses the command's ambient authentication. Tests mock AD queries and verify filter construction; no live domain query is tested.
Get-ScriptDirectory and Get-ScriptName resolve the immediately calling script rather than the module implementation file. Calls inside a function defined in a script use that defining script; a nested or dot-sourced script uses its own path. Calls made interactively without an explicit path return no output. They do not read the historical, externally supplied hostinvocation variable.
# Inside automation.ps1:
$scriptDirectory = Get-ScriptDirectory
$scriptName = Get-ScriptName
# Explicit paths also work interactively, including paths that do not yet exist:
Get-ScriptDirectory -ScriptPath './scripts/automation.ps1'
'./scripts/automation.ps1', './scripts/other.ps1' | Get-ScriptNameScriptPath accepts literal absolute/relative filesystem filenames and pipeline input. Relative paths use the current PowerShell location, not the caller's directory. Wildcard characters are treated literally. Non-filesystem provider paths and paths without a filename throw; no existence, extension or file-type check is performed. Unlike the legacy implementations, these helpers do not depend on script-scoped MyInvocation or silently return a module filename.
WinSCP/SCP and PGP/OpenPGP are separate module projects. No transfer backend or PGP backend is bundled into this module; AES-GCM string encryption remains independent.
The AzureAD helper has been removed; use Microsoft Graph or Microsoft Entra PowerShell directly. The legacy Exchange wrappers have been removed; use ExchangeOnlineManagement directly for Exchange Online. The process-wide certificate-bypass snippet has been removed. Import regression tests verify that loading and reloading IT-ToolBox leaves TLS callbacks, service sessions and caller preferences alone, and excludes archived and staged code. See the integration review for defects, service-specific migration directions and requirements for future wrappers.
Report reproducible bugs through GitHub Issues. Include the command, expected and actual behavior, operating system, PowerShell version and repository commit. Remove credentials and private data from examples. See CONTRIBUTING.md for the branch and test workflow.