Careful with Arrays

by Nov 29, 2022

Categories

Tags

Administration agent-based monitoring Agentless Monitoring alert responses alert thresholds alerting Alerts Amazon Aurora Amazon EC2 Amazon RDS Amazon RDS / Aurora Amazon RDS for SQL Server Amazon Redshift Amazon S3 Amazon Web Services (AWS) Analytics application monitoring Aqua Data Studio automation availability Azure Azure SQL Database azure sql managed instance Azure VM backup Backup and recovery backup and restore backup compression backup status Backup Strategy backups big data Blocking bug fixes business architecture business data objects business intelligence business process modeling business process models capacity planning change management cloud cloud database cloud database monitoring cloud infrastructure cloud migration cloud providers Cloud Readiness Cloud Services cloud storage cloud virtual machine cloud VM clusters code completion collaboration compliance compliance audit compliance audits compliance manager compliance reporting conference configuration connect to database cpu Cross Platform custom counters Custom Views customer survey customer testimonials Dark Theme dashboards data analysis Data Analytics data architect data architecture data breaches Data Collector data governance data lakes data lineage data management data model data modeler data modeling data models data privacy data protection data security data security measures data sources data visualization data warehouse database database administration database administrator database automation database backup database backups database capacity database changes database community database connection database design database developer database developers database development database diversity Database Engine Tuning Advisor database fragmentation database GUI database IDE database indexes database inventory management database locks database management database migration database monitoring database navigation database optimization database performance Database Permissions database platforms database profiling database queries database recovery database replication database restore database schema database security database support database synchronization database tools database transactions database tuning database-as-a-service databases DB Change Manager DB Optimizer DB PowerStudio DB2 DBA DBaaS DBArtisan dBase DBMS DDL Debugging defragmentation Demo diagnostic manager diagnostics dimensional modeling disaster recovery Download drills embedded database Encryption End-user Experience entity-relationship model ER/Studio ER/Studio Data Architect ER/Studio Enterprise Team Edition events execution plans free tools galera cluster GDPR Getting Started Git GitHub Google Cloud Hadoop Healthcare high availability HIPAA Hive hybrid clouds Hyper-V IDERA IDERA ACE Index Analyzer index optimization infrastructure as a service (IaaS) infrastructure monitoring installation Integrated Development Environment interbase Inventory Manager IT infrastructure Java JD Edwards JSON licensing load test load testing logical data model macOS macros managed cloud database managed cloud databases MariaDB memory memorystorage memoryusage metadata metric baselines metric thresholds Microsoft Azure Microsoft Azure SQL Database Microsoft PowerShell Microsoft SQL Server Microsoft Windows MongoDB monitoring Monitoring Tools Monyog multiple platforms MySQL news newsletter NoSQL Notifications odbc optimization Oracle PeopleSoft performance Performance Dashboards performance metrics performance monitoring performance schema performance tuning personally identifiable information physical data model Platform platform as a service (PaaS) PostgreSQL Precise Precise for Databases Precise for Oracle Precise for SQL Server Precise Management Database (PMDB) product updates Project Migration public clouds Query Analyzer query builder query monitor query optimization query performance Query Store query tool query tuning query-level waits Rapid SQL rdbms real time monitoring Real User Monitoring recovery regulations relational databases Releases Reporting Reports repository Restore reverse engineering Roadmap sample SAP Scalability Security Policy Security Practices server monitoring Server performance server-level waits Service Level Agreement SkySQL slow query SNMP snowflake source control SQL SQL Admin Toolset SQL CM SQL code SQL coding SQL Compliance Manager SQL Defrag Manager sql development SQL Diagnostic Manager SQL Diagnostic Manager for MySQL SQL Diagnostic Manager for SQL Server SQL Diagnostic Manager Pro SQL DM SQL Doctor SQL Enterprise Job Manager SQl IM SQL Inventory Manager SQL Management Suite SQL Monitoring SQL Performance SQL Quality SQL query SQL Query Tuner SQL Safe Backup SQL script SQL Secure SQL Security Suite SQL Server sql server alert SQL Server Migration SQL Server Performance SQL Server Recommendations SQL Server Security SQL statement history SQL tuning SQL Virtual Database sqlmemory sqlserver SQLyog Storage Storage Performance structured data Subversion Support tempdb tempdb data temporal data Tips and Tricks troubleshooting universal data models universal mapping unstructured data Uptime Infrastructure Monitor user experience user permissions Virtual Machine (VM) web services webinar What-if analysis WindowsPowerShell

Careful with Arrays

With PowerShell you never know whether a cmdlet returns an array or a single object. That’s because PowerShell automatically wraps results in an array once a command returns more than one item:

# no array:
$test = Get-Service -Name Spooler
$test -is [Array]

# array:
$test = Get-Service -Name S*
$test -is [Array]

It’s critical to understand this because it means that runtime conditions can determine the nature of a variable. And this can cause bad things. Here is just one example to illustrate the problem:

Below code returns all service names that start with a “c”, then grabs the first one. That’s possible because there is more than just one service starting with “c”, so PowerShell returns an array in $servicenames, and you can then use a numeric index into this array to pick specific elements:

$Name = 'c*'

# get service names
$servicenames = Get-Service -Name $Name | Select-Object -ExpandProperty Name

# get first service name
$servicenames[0]

You cannot assume that $servicenames is always an array, though. If during runtime there is just exactly one service matching your request, the result is no longer an array but instead it would be the service name directly.

Why (and when) does that matter? It starts to matter the moment your code employs specific array functionality because that functionality may not exist in certain scenarios or behave differently.

To illustrate this, below code lists all services starting with “cry” now. Just one service matches the request. Therefore, $servicenames no longer is an array. It is now a string. When you use an index on a string, you get back a particular letter from that string.

The very same code now produces a single character instead of a service name:

$Name = 'cry*'

# get service names
$servicenames = Get-Service -Name $Name | Select-Object -ExpandProperty Name

# get first service name
$servicenames[0]

These examples may seem a bit constructed but you can find the underlying issue at the core of many hard-to-find script errors. That’s why it is important to always ensure that you actually get an array when your code uses array features.

One simple way of ensuring that you get an array is the construct @(): anything in the parenthesis is returned as an array. That’s why below code works regardless of whether the command returns one or more results:

$Name = 'cry*'

# get service names
$servicenames = @(Get-Service -Name $Name | Select-Object -ExpandProperty Name)

# get first service name
$servicenames[0]

To add a digital signature to a PowerShell script file (or any other file that is capable of carrying a digital signature for this matter), use Set-AuthenticodeSignature. Run the demo code below (adjust paths to file and certificate as needed):

$Name = 'cry*'

# get service names
[array]$servicenames = Get-Service -Name $Name | Select-Object -ExpandProperty Name

# get first service name
$servicenames[0]

When you run this code, the script file specified in $Path opens and shows the digital signature that was added to the bottom of your script:

Hello World!

$Name = 'cry*'

# get service names
[string[]]$servicenames = Get-Service -Name $Name | Select-Object -ExpandProperty Name

# get first service name
$servicenames[0]

However, [array] is much easier to use because it always works regardless of data type, and [array] is also easier to understand to users not familiar with types.

 


Twitter This Tip! ReTweet this Tip!