I recently ran into an issue where sometimes when I would attempt to query or write to an Azure Storage table I would receive an error similar to the ones below.
- Cannot find an overload for “Insert” and the argument count: “1”.
- Cannot find an overload for “ExecuteQuery” and the argument count: “1”.
The strange thing is only seemed to happen on certain machines or scripts. Then I found this bug report on GitHub talking about just that. It turns out this can happen when you have both the Azure.Storage and AzureRM.Storage modules loaded at the same time. It appears there are two different versions of the DLL file Microsoft.WindowsAzure.Storage.dll. In some cases, it would grab the Azure one and in other cases it would grab the AzureRM one. The problem is the Azure.Storage module is required to query or write to a storage table, whether or not the storage account is a Classic or Resource Manager (RM) account.
The development team is aware of this, and are working on a fix. However, in the meantime, there is a workaround you can use to ensure your scripts will work.
What you need to do is to force any query and entity objects to use the same version of the Microsoft.WindowsAzure.Storage.dll file, as the Azure.Storage module. You can do this by saving the version information to a variable, and then specifying it when you create these objects.
If you look at the example below of a table query, you’ll see on line 8 we create the $assemblySN variable with the assembly’s full name. Then on line 11, we add that to the New-Object command for creating the query object from the TableQuery class.
#Define the storage account and context. $Ctx = New-AzureStorageContext -StorageAccountName $StorageAccountName -StorageAccountKey $StorageAccountKey #Get a reference to a table. $table = Get-AzureStorageTable -Name $TableName -Context $Ctx #get the $table Assembly FullName $assemblySN = $table.CloudTable.GetType().Assembly.FullName #Create a table query. $query = New-Object -TypeName "Microsoft.WindowsAzure.Storage.Table.TableQuery,$assemblySN" #Execute the query. $entities = $table.CloudTable.ExecuteQuery($query)
When you want to write or delete rows from the table you need to use the TableOperation and the DynamicTableEntity classes. For the DynamicTableEntity you can use the same trick, you used with the TableQuery above. See line 11 below. However, you cannot call TableOperation class using the New-Object cmdlet, like you can with the other classes. In this case you can use the Invoke-Expression cmdlet to load the class with the specific version. You can see this on line 14 of the example below.
#Define the storage account and context. $Ctx = New-AzureStorageContext -StorageAccountName $StorageAccountName -StorageAccountKey $StorageAccountKey #Get a reference to a table. $table = Get-AzureStorageTable -Name $TableName -Context $Ctx #get the $table Assembly FullName $assemblySN = $table.CloudTable.GetType().Assembly.FullName #Execute the Insert. $entity = New-Object -TypeName "Microsoft.WindowsAzure.Storage.Table.DynamicTableEntity,$assemblySN" -ArgumentList $partitionKey, $rowKey $entity.Properties.Add("columnA", $columnA) $entity.Properties.Add("columnB", $columnB) $result = $table.CloudTable.Execute((invoke-expression "[Microsoft.WindowsAzure.Storage.Table.TableOperation,$assemblySN]::InsertOrReplace(`$entity)"))
Hopefully, we’ll get a cleaner solution to this in the future, but for now, this solution is working both locally and in Azure Automation. Thanks to the Microsoft team on GitHub for working with me and others to get us functioning while they work on a permanent fix.